Main Page | Data Structures | Directories | File List | Data Fields

wifidog-1.1.1/src/centralserver.c

00001 /********************************************************************\
00002  * This program is free software; you can redistribute it and/or    *
00003  * modify it under the terms of the GNU General Public License as   *
00004  * published by the Free Software Foundation; either version 2 of   *
00005  * the License, or (at your option) any later version.              *
00006  *                                                                  *
00007  * This program is distributed in the hope that it will be useful,  *
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00010  * GNU General Public License for more details.                     *
00011  *                                                                  *
00012  * You should have received a copy of the GNU General Public License*
00013  * along with this program; if not, contact:                        *
00014  *                                                                  *
00015  * Free Software Foundation           Voice:  +1-617-542-5942       *
00016  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
00017  * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
00018  *                                                                  *
00019  \********************************************************************/
00020 
00021 /* $Header: /cvsroot/wifidog/wifidog/src/centralserver.c,v 1.36 2005/02/25 04:03:38 minaguib Exp $ */
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <sys/types.h>
00030 #include <sys/socket.h>
00031 #include <sys/stat.h>
00032 #include <netinet/in.h>
00033 #include <arpa/inet.h>
00034 #include <errno.h>
00035 #include <unistd.h>
00036 #include <string.h>
00037 #include <syslog.h>
00038 
00039 #include "httpd.h"
00040 
00041 #include "common.h"
00042 #include "safe.h"
00043 #include "util.h"
00044 #include "auth.h"
00045 #include "conf.h"
00046 #include "debug.h"
00047 #include "centralserver.h"
00048 #include "../config.h"
00049 
00050 extern pthread_mutex_t  config_mutex;
00051 
00061 t_authcode
00062 auth_server_request(t_authresponse *authresponse, char *request_type, char *ip, char *mac, char *token, unsigned long long int incoming, unsigned long long int outgoing)
00063 {
00064         int sockfd;
00065         size_t  numbytes, totalbytes;
00066         char buf[MAX_BUF];
00067         char *tmp;
00068 
00069         /* Blanket default is error. */
00070         authresponse->authcode = AUTH_ERROR;
00071         
00072         sockfd = connect_auth_server();
00073         if (sockfd == -1) {
00074                 /* Could not connect to any auth server */
00075                 return (AUTH_ERROR);
00076         }
00077 
00082         memset(buf, 0, sizeof(buf));
00083         snprintf(buf, (sizeof(buf) - 1), "GET %sauth/?stage=%s&ip=%s&mac=%s&token=%s&incoming=%llu&outgoing=%llu HTTP/1.0\n"
00084                 "User-Agent: WiFiDog %s\n"
00085                 "Host: %s\n"
00086                 "\n",
00087             config_get_config()->auth_servers->authserv_path, request_type, ip, mac, token, incoming, outgoing,
00088                                 VERSION, 
00089             config_get_config()->auth_servers->authserv_hostname
00090                  );
00091 
00092         debug(LOG_DEBUG, "Sending HTTP request to auth server: [%s]\n", buf);
00093         send(sockfd, buf, strlen(buf), 0);
00094 
00095         numbytes = totalbytes = 0;
00096         while ((numbytes = read(sockfd, buf + totalbytes, MAX_BUF - (totalbytes + 1))) > 0)
00097                 totalbytes += numbytes;
00098         
00099         if (numbytes == -1) {
00100                 debug(LOG_ERR, "Error reading from auth server: %s", strerror(errno));
00101                 close(sockfd);
00102                 return(AUTH_ERROR);
00103         }
00104         close(sockfd);
00105 
00106         buf[totalbytes] = '\0';
00107         debug(LOG_DEBUG, "HTTP Response from Server: [%s]", buf);
00108         
00109         if ((tmp = strstr(buf, "Auth: "))) {
00110                 if (sscanf(tmp, "Auth: %d", (int *)&authresponse->authcode) == 1) {
00111                         debug(LOG_INFO, "Auth server returned authentication code %d", authresponse->authcode);
00112                         return(authresponse->authcode);
00113                 } else {
00114                         debug(LOG_WARNING, "Auth server did not return expected authentication code");
00115                         return(AUTH_ERROR);
00116                 }
00117         }
00118         else {
00119                 return(AUTH_ERROR);
00120         }
00121 
00122         return(AUTH_ERROR);
00123 }
00124 
00125 /* Tries really hard to connect to an auth server. Returns a file descriptor, -1 on error
00126  */
00127 int connect_auth_server() {
00128         int sockfd;
00129 
00130         LOCK_CONFIG();
00131         sockfd = _connect_auth_server(0);
00132         UNLOCK_CONFIG();
00133 
00134         if (sockfd == -1) {
00135                 debug(LOG_ERR, "Failed to connect to any of the auth servers");
00136                 mark_auth_offline();
00137         }
00138         else {
00139                 debug(LOG_DEBUG, "Connected to auth server");
00140                 mark_auth_online();
00141         }
00142         return (sockfd);
00143 }
00144 
00145 /* Helper function called by connect_auth_server() to do the actual work including recursion - do not call directly
00146 @param level recursion level indicator
00147  */
00148 int _connect_auth_server(int level) {
00149         s_config *config = config_get_config();
00150         t_auth_serv *auth_server = NULL;
00151         struct in_addr *h_addr;
00152         int num_servers = 0;
00153         char * hostname = NULL;
00154         char * popular_servers[] = {
00155                   "www.google.com"
00156                 , "www.yahoo.com"
00157                 , NULL
00158         };
00159         char ** popularserver;
00160         char * ip;
00161         struct sockaddr_in their_addr;
00162         int sockfd;
00163 
00164         level++;
00165 
00166         /*
00167          * Let's calculate the number of servers we have
00168          */
00169         for (auth_server = config->auth_servers; auth_server; auth_server = auth_server->next) {
00170                 num_servers++;
00171         }
00172         debug(LOG_DEBUG, "Level %d: Calculated %d auth servers in list", level, num_servers);
00173 
00174         if (level > num_servers) {
00175                 /*
00176                  * We've called ourselves too many times
00177                  * That means we've cycled through all the servers in the server list at least once and none are accessible
00178                  */
00179                 return (-1);
00180         }
00181 
00182         /*
00183          * Let's resolve the hostname of the top server to an IP address
00184          */
00185         auth_server = config->auth_servers;
00186         hostname = auth_server->authserv_hostname;
00187         debug(LOG_DEBUG, "Level %d: Resolving auth server [%s]", level, hostname);
00188         h_addr = wd_gethostbyname(hostname);
00189         if (!h_addr) {
00190                 /*
00191                  * DNS resolving it failed
00192                  *
00193                  * Can we resolve any of the popular servers ?
00194                  */
00195                 debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] failed", level, hostname);
00196 
00197                 for (popularserver = popular_servers; *popularserver; popularserver++) {
00198                         debug(LOG_DEBUG, "Level %d: Resolving popular server [%s]", level, *popularserver);
00199                         h_addr = wd_gethostbyname(*popularserver);
00200                         if (h_addr) {
00201                                 debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] succeeded = [%s]", level, *popularserver, inet_ntoa(*h_addr));
00202                                 break;
00203                         }
00204                         else {
00205                                 debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] failed", level, *popularserver);
00206                         }
00207                 }
00208 
00209                 if (h_addr) {
00210                         free (h_addr);
00211                         /*
00212                          * Yes
00213                          *
00214                          * The auth server's DNS server is probably dead. Try the next auth server
00215                          */
00216                         debug(LOG_DEBUG, "Level %d: Marking auth server [%s] as bad and trying next if possible", level, hostname);
00217                         if (auth_server->last_ip) {
00218                                 free(auth_server->last_ip);
00219                                 auth_server->last_ip = NULL;
00220                         }
00221                         mark_auth_server_bad(auth_server);
00222                         return _connect_auth_server(level);
00223                 }
00224                 else {
00225                         /*
00226                          * No
00227                          *
00228                          * It's probably safe to assume that the internet connection is malfunctioning
00229                          * and nothing we can do will make it work
00230                          */
00231                         mark_offline();
00232                         debug(LOG_DEBUG, "Level %d: Failed to resolve auth server and all popular servers. The internet connection is probably down", level);
00233                         return(-1);
00234                 }
00235         }
00236         else {
00237                 /*
00238                  * DNS resolving was successful
00239                  */
00240                 ip = safe_strdup(inet_ntoa(*h_addr));
00241                 debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] succeeded = [%s]", level, hostname, ip);
00242 
00243                 if (!auth_server->last_ip || strcmp(auth_server->last_ip, ip) != 0) {
00244                         /*
00245                          * But the IP address is different from the last one we knew
00246                          * Update it
00247                          */
00248                         debug(LOG_DEBUG, "Level %d: Updating last_ip IP of server [%s] to [%s]", level, hostname, ip);
00249                         if (auth_server->last_ip) free(auth_server->last_ip);
00250                         auth_server->last_ip = ip;
00251 
00252                         /* Update firewall rules */
00253                         fw_clear_authservers();
00254                         fw_set_authservers();
00255                 }
00256                 else {
00257                         /*
00258                          * IP is the same as last time
00259                          */
00260                         free(ip);
00261                 }
00262 
00263                 /*
00264                  * Connect to it
00265                  */
00266                 debug(LOG_DEBUG, "Level %d: Connecting to auth server %s:%d", level, hostname, auth_server->authserv_http_port);
00267                 their_addr.sin_family = AF_INET;
00268                 their_addr.sin_port = htons(auth_server->authserv_http_port);
00269                 their_addr.sin_addr = *h_addr;
00270                 memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero));
00271                 free (h_addr);
00272 
00273                 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
00274                         debug(LOG_ERR, "Level %d: Failed to create a new SOCK_STREAM socket: %s", strerror(errno));
00275                         return(-1);
00276                 }
00277 
00278                 if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
00279                         /*
00280                          * Failed to connect
00281                          * Mark the server as bad and try the next one
00282                          */
00283                         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));
00284                         close(sockfd);
00285                         mark_auth_server_bad(auth_server);
00286                         return _connect_auth_server(level);
00287                 }
00288                 else {
00289                         /*
00290                          * We have successfully connected
00291                          */
00292                         debug(LOG_DEBUG, "Level %d: Successfully connected to auth server %s:%d", level, hostname, auth_server->authserv_http_port);
00293                         return sockfd;
00294                 }
00295         }
00296 }
00297 
00298 /* config->authserv_maxtries */

Generated on Sun Apr 3 20:04:45 2005 for WifiDog by  doxygen 1.4.1