⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 centralserver.c.svn-base

📁 The Wifidog project is an open source captive portal solution. It was designed primarily for wireles
💻 SVN-BASE
字号:
/********************************************************************\ * This program is free software; you can redistribute it and/or    * * modify it under the terms of the GNU General Public License as   * * published by the Free Software Foundation; either version 2 of   * * the License, or (at your option) any later version.              * *                                                                  * * This program is distributed in the hope that it will be useful,  * * but WITHOUT ANY WARRANTY; without even the implied warranty of   * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    * * GNU General Public License for more details.                     * *                                                                  * * You should have received a copy of the GNU General Public License* * along with this program; if not, contact:                        * *                                                                  * * Free Software Foundation           Voice:  +1-617-542-5942       * * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       * * Boston, MA  02111-1307,  USA       gnu@gnu.org                   * *                                                                  * \********************************************************************//* $Id$ *//** @file centralserver.c  @brief Functions to talk to the central server (auth/send stats/get rules/etc...)  @author Copyright (C) 2004 Philippe April <papril777@yahoo.com> */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <unistd.h>#include <string.h>#include <syslog.h>#include "httpd.h"#include "common.h"#include "safe.h"#include "util.h"#include "auth.h"#include "conf.h"#include "debug.h"#include "centralserver.h"#include "../config.h"extern pthread_mutex_t	config_mutex;/** Initiates a transaction with the auth server, either to authenticate or to * update the traffic counters at the server@param authresponse Returns the information given by the central server @param request_type Use the REQUEST_TYPE_* defines in centralserver.h@param ip IP adress of the client this request is related to@param mac MAC adress of the client this request is related to@param token Authentification token of the client@param incoming Current counter of the client's total incoming traffic, in bytes @param outgoing Current counter of the client's total outgoing traffic, in bytes */t_authcodeauth_server_request(t_authresponse *authresponse, char *request_type, char *ip, char *mac, char *token, unsigned long long int incoming, unsigned long long int outgoing){	int sockfd;	size_t	numbytes, totalbytes;	char buf[MAX_BUF];	char *tmp;	int done, nfds;	fd_set			readfds;	struct timeval		timeout;	t_auth_serv	*auth_server = NULL;	auth_server = get_auth_server();		/* Blanket default is error. */	authresponse->authcode = AUTH_ERROR;		sockfd = connect_auth_server();	if (sockfd == -1) {		/* Could not connect to any auth server */		return (AUTH_ERROR);	}	/**	 * TODO: XXX change the PHP so we can harmonize stage as request_type	 * everywhere.	 */	memset(buf, 0, sizeof(buf));	snprintf(buf, (sizeof(buf) - 1),		"GET %s%sstage=%s&ip=%s&mac=%s&token=%s&incoming=%llu&outgoing=%llu HTTP/1.0\r\n"		"User-Agent: WiFiDog %s\r\n"		"Host: %s\r\n"		"\r\n",		auth_server->authserv_path,		auth_server->authserv_auth_script_path_fragment,		request_type,		ip,		mac,		token,		incoming,		outgoing,		VERSION,		auth_server->authserv_hostname	);	debug(LOG_DEBUG, "Sending HTTP request to auth server: [%s]\n", buf);	send(sockfd, buf, strlen(buf), 0);	debug(LOG_DEBUG, "Reading response");	numbytes = totalbytes = 0;	done = 0;	do {		FD_ZERO(&readfds);		FD_SET(sockfd, &readfds);		timeout.tv_sec = 30; /* XXX magic... 30 second is as good a timeout as any */		timeout.tv_usec = 0;		nfds = sockfd + 1;		nfds = select(nfds, &readfds, NULL, NULL, &timeout);		if (nfds > 0) {			/** We don't have to use FD_ISSET() because there			 *  was only one fd. */			numbytes = read(sockfd, buf + totalbytes, MAX_BUF - (totalbytes + 1));			if (numbytes < 0) {				debug(LOG_ERR, "An error occurred while reading from auth server: %s", strerror(errno));				/* FIXME */				close(sockfd);				return (AUTH_ERROR);			}			else if (numbytes == 0) {				done = 1;			}			else {				totalbytes += numbytes;				debug(LOG_DEBUG, "Read %d bytes, total now %d", numbytes, totalbytes);			}		}		else if (nfds == 0) {			debug(LOG_ERR, "Timed out reading data via select() from auth server");			/* FIXME */			close(sockfd);			return (AUTH_ERROR);		}		else if (nfds < 0) {			debug(LOG_ERR, "Error reading data via select() from auth server: %s", strerror(errno));			/* FIXME */			close(sockfd);			return (AUTH_ERROR);		}	} while (!done);	close(sockfd);	buf[totalbytes] = '\0';	debug(LOG_DEBUG, "HTTP Response from Server: [%s]", buf);		if ((tmp = strstr(buf, "Auth: "))) {		if (sscanf(tmp, "Auth: %d", (int *)&authresponse->authcode) == 1) {			debug(LOG_INFO, "Auth server returned authentication code %d", authresponse->authcode);			return(authresponse->authcode);		} else {			debug(LOG_WARNING, "Auth server did not return expected authentication code");			return(AUTH_ERROR);		}	}	else {		return(AUTH_ERROR);	}	/* XXX Never reached because of the above if()/else pair. */	return(AUTH_ERROR);}/* Tries really hard to connect to an auth server. Returns a file descriptor, -1 on error */int connect_auth_server() {	int sockfd;	LOCK_CONFIG();	sockfd = _connect_auth_server(0);	UNLOCK_CONFIG();	if (sockfd == -1) {		debug(LOG_ERR, "Failed to connect to any of the auth servers");		mark_auth_offline();	}	else {		debug(LOG_DEBUG, "Connected to auth server");		mark_auth_online();	}	return (sockfd);}/* Helper function called by connect_auth_server() to do the actual work including recursion * DO NOT CALL DIRECTLY @param level recursion level indicator must be 0 when not called by _connect_auth_server() */int _connect_auth_server(int level) {	s_config *config = config_get_config();	t_auth_serv *auth_server = NULL;	struct in_addr *h_addr;	int num_servers = 0;	char * hostname = NULL;	char * popular_servers[] = {		  "www.google.com",		  "www.yahoo.com",		  NULL	};	char ** popularserver;	char * ip;	struct sockaddr_in their_addr;	int sockfd;	/* XXX level starts out at 0 and gets incremented by every iterations. */	level++;	/*	 * Let's calculate the number of servers we have	 */	for (auth_server = config->auth_servers; auth_server; auth_server = auth_server->next) {		num_servers++;	}	debug(LOG_DEBUG, "Level %d: Calculated %d auth servers in list", level, num_servers);	if (level > num_servers) {		/*		 * We've called ourselves too many times		 * This means we've cycled through all the servers in the server list		 * at least once and none are accessible		 */		return (-1);	}	/*	 * Let's resolve the hostname of the top server to an IP address	 */	auth_server = config->auth_servers;	hostname = auth_server->authserv_hostname;	debug(LOG_DEBUG, "Level %d: Resolving auth server [%s]", level, hostname);	h_addr = wd_gethostbyname(hostname);	if (!h_addr) {		/*		 * DNS resolving it failed		 *		 * Can we resolve any of the popular servers ?		 */		debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] failed", level, hostname);		for (popularserver = popular_servers; *popularserver; popularserver++) {			debug(LOG_DEBUG, "Level %d: Resolving popular server [%s]", level, *popularserver);			h_addr = wd_gethostbyname(*popularserver);			if (h_addr) {				debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] succeeded = [%s]", level, *popularserver, inet_ntoa(*h_addr));				break;			}			else {				debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] failed", level, *popularserver);			}		}		/* 		 * If we got any h_addr buffer for one of the popular servers, in other		 * words, if one of the popular servers resolved, we'll assume the DNS		 * works, otherwise we'll deal with net connection or DNS failure.		 */		if (h_addr) {			free (h_addr);			/*			 * Yes			 *			 * The auth server's DNS server is probably dead. Try the next auth server			 */			debug(LOG_DEBUG, "Level %d: Marking auth server [%s] as bad and trying next if possible", level, hostname);			if (auth_server->last_ip) {				free(auth_server->last_ip);				auth_server->last_ip = NULL;			}			mark_auth_server_bad(auth_server);			return _connect_auth_server(level);		}		else {			/*			 * No			 *			 * It's probably safe to assume that the internet connection is malfunctioning			 * and nothing we can do will make it work			 */			mark_offline();			debug(LOG_DEBUG, "Level %d: Failed to resolve auth server and all popular servers. "					"The internet connection is probably down", level);			return(-1);		}	}	else {		/*		 * DNS resolving was successful		 */		ip = safe_strdup(inet_ntoa(*h_addr));		debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] succeeded = [%s]", level, hostname, ip);		if (!auth_server->last_ip || strcmp(auth_server->last_ip, ip) != 0) {			/*			 * But the IP address is different from the last one we knew			 * Update it			 */			debug(LOG_DEBUG, "Level %d: Updating last_ip IP of server [%s] to [%s]", level, hostname, ip);			if (auth_server->last_ip) free(auth_server->last_ip);			auth_server->last_ip = ip;			/* Update firewall rules */			fw_clear_authservers();			fw_set_authservers();		}		else {			/*			 * IP is the same as last time			 */			free(ip);		}		/*		 * Connect to it		 */		debug(LOG_DEBUG, "Level %d: Connecting to auth server %s:%d", level, hostname, auth_server->authserv_http_port);		their_addr.sin_family = AF_INET;		their_addr.sin_port = htons(auth_server->authserv_http_port);		their_addr.sin_addr = *h_addr;		memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero));		free (h_addr);		if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {			debug(LOG_ERR, "Level %d: Failed to create a new SOCK_STREAM socket: %s", strerror(errno));			return(-1);		}		if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {			/*			 * Failed to connect			 * Mark the server as bad and try the next one			 */			debug(LOG_DEBUG, "Level %d: Failed to connect to auth server %s:%d (%s). Marking it as bad and trying next if possible", level, hostname, auth_server->authserv_http_port, strerror(errno));			close(sockfd);			mark_auth_server_bad(auth_server);			return _connect_auth_server(level); /* Yay recursion! */		}		else {			/*			 * We have successfully connected			 */			debug(LOG_DEBUG, "Level %d: Successfully connected to auth server %s:%d", level, hostname, auth_server->authserv_http_port);			return sockfd;		}	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -