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

wifidog-1.1.2/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.38 2005/05/17 02:58:20 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         int done, nfds;
00069         fd_set                  readfds;
00070         struct timeval          timeout;
00071 
00072         /* Blanket default is error. */
00073         authresponse->authcode = AUTH_ERROR;
00074         
00075         sockfd = connect_auth_server();
00076         if (sockfd == -1) {
00077                 /* Could not connect to any auth server */
00078                 return (AUTH_ERROR);
00079         }
00080 
00085         memset(buf, 0, sizeof(buf));
00086         snprintf(buf, (sizeof(buf) - 1), "GET %sauth/?stage=%s&ip=%s&mac=%s&token=%s&incoming=%llu&outgoing=%llu HTTP/1.0\r\n"
00087                 "User-Agent: WiFiDog %s\r\n"
00088                 "Host: %s\r\n"
00089                 "\r\n",
00090                 config_get_config()->auth_servers->authserv_path, request_type, ip, mac, token, incoming, outgoing,
00091                 VERSION, 
00092                 config_get_config()->auth_servers->authserv_hostname
00093         );
00094 
00095         debug(LOG_DEBUG, "Sending HTTP request to auth server: [%s]\n", buf);
00096         send(sockfd, buf, strlen(buf), 0);
00097 
00098         debug(LOG_DEBUG, "Reading response");
00099         numbytes = totalbytes = 0;
00100         done = 0;
00101         do {
00102                 FD_ZERO(&readfds);
00103                 FD_SET(sockfd, &readfds);
00104                 timeout.tv_sec = 30; /* XXX magic... 30 second */
00105                 timeout.tv_usec = 0;
00106                 nfds = sockfd + 1;
00107 
00108                 nfds = select(nfds, &readfds, NULL, NULL, &timeout);
00109 
00110                 if (nfds > 0) {
00113                         numbytes = read(sockfd, buf + totalbytes, MAX_BUF - (totalbytes + 1));
00114                         if (numbytes < 0) {
00115                                 debug(LOG_ERR, "An error occurred while reading from auth server: %s", strerror(errno));
00116                                 /* FIXME */
00117                                 close(sockfd);
00118                                 return (AUTH_ERROR);
00119                         }
00120                         else if (numbytes == 0) {
00121                                 done = 1;
00122                         }
00123                         else {
00124                                 totalbytes += numbytes;
00125                                 debug(LOG_DEBUG, "Read %d bytes, total now %d", numbytes, totalbytes);
00126                         }
00127                 }
00128                 else if (nfds == 0) {
00129                         debug(LOG_ERR, "Timed out reading data via select() from auth server");
00130                         /* FIXME */
00131                         close(sockfd);
00132                         return (AUTH_ERROR);
00133                 }
00134                 else if (nfds < 0) {
00135                         debug(LOG_ERR, "Error reading data via select() from auth server: %s", strerror(errno));
00136                         /* FIXME */
00137                         close(sockfd);
00138                         return (AUTH_ERROR);
00139                 }
00140         } while (!done);
00141 
00142         close(sockfd);
00143 
00144         buf[totalbytes] = '\0';
00145         debug(LOG_DEBUG, "HTTP Response from Server: [%s]", buf);
00146         
00147         if ((tmp = strstr(buf, "Auth: "))) {
00148                 if (sscanf(tmp, "Auth: %d", (int *)&authresponse->authcode) == 1) {
00149                         debug(LOG_INFO, "Auth server returned authentication code %d", authresponse->authcode);
00150                         return(authresponse->authcode);
00151                 } else {
00152                         debug(LOG_WARNING, "Auth server did not return expected authentication code");
00153                         return(AUTH_ERROR);
00154                 }
00155         }
00156         else {
00157                 return(AUTH_ERROR);
00158         }
00159 
00160         return(AUTH_ERROR);
00161 }
00162 
00163 /* Tries really hard to connect to an auth server. Returns a file descriptor, -1 on error
00164  */
00165 int connect_auth_server() {
00166         int sockfd;
00167 
00168         LOCK_CONFIG();
00169         sockfd = _connect_auth_server(0);
00170         UNLOCK_CONFIG();
00171 
00172         if (sockfd == -1) {
00173                 debug(LOG_ERR, "Failed to connect to any of the auth servers");
00174                 mark_auth_offline();
00175         }
00176         else {
00177                 debug(LOG_DEBUG, "Connected to auth server");
00178                 mark_auth_online();
00179         }
00180         return (sockfd);
00181 }
00182 
00183 /* Helper function called by connect_auth_server() to do the actual work including recursion - do not call directly
00184 @param level recursion level indicator
00185  */
00186 int _connect_auth_server(int level) {
00187         s_config *config = config_get_config();
00188         t_auth_serv *auth_server = NULL;
00189         struct in_addr *h_addr;
00190         int num_servers = 0;
00191         char * hostname = NULL;
00192         char * popular_servers[] = {
00193                   "www.google.com"
00194                 , "www.yahoo.com"
00195                 , NULL
00196         };
00197         char ** popularserver;
00198         char * ip;
00199         struct sockaddr_in their_addr;
00200         int sockfd;
00201 
00202         level++;
00203 
00204         /*
00205          * Let's calculate the number of servers we have
00206          */
00207         for (auth_server = config->auth_servers; auth_server; auth_server = auth_server->next) {
00208                 num_servers++;
00209         }
00210         debug(LOG_DEBUG, "Level %d: Calculated %d auth servers in list", level, num_servers);
00211 
00212         if (level > num_servers) {
00213                 /*
00214                  * We've called ourselves too many times
00215                  * That means we've cycled through all the servers in the server list at least once and none are accessible
00216                  */
00217                 return (-1);
00218         }
00219 
00220         /*
00221          * Let's resolve the hostname of the top server to an IP address
00222          */
00223         auth_server = config->auth_servers;
00224         hostname = auth_server->authserv_hostname;
00225         debug(LOG_DEBUG, "Level %d: Resolving auth server [%s]", level, hostname);
00226         h_addr = wd_gethostbyname(hostname);
00227         if (!h_addr) {
00228                 /*
00229                  * DNS resolving it failed
00230                  *
00231                  * Can we resolve any of the popular servers ?
00232                  */
00233                 debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] failed", level, hostname);
00234 
00235                 for (popularserver = popular_servers; *popularserver; popularserver++) {
00236                         debug(LOG_DEBUG, "Level %d: Resolving popular server [%s]", level, *popularserver);
00237                         h_addr = wd_gethostbyname(*popularserver);
00238                         if (h_addr) {
00239                                 debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] succeeded = [%s]", level, *popularserver, inet_ntoa(*h_addr));
00240                                 break;
00241                         }
00242                         else {
00243                                 debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] failed", level, *popularserver);
00244                         }
00245                 }
00246 
00247                 if (h_addr) {
00248                         free (h_addr);
00249                         /*
00250                          * Yes
00251                          *
00252                          * The auth server's DNS server is probably dead. Try the next auth server
00253                          */
00254                         debug(LOG_DEBUG, "Level %d: Marking auth server [%s] as bad and trying next if possible", level, hostname);
00255                         if (auth_server->last_ip) {
00256                                 free(auth_server->last_ip);
00257                                 auth_server->last_ip = NULL;
00258                         }
00259                         mark_auth_server_bad(auth_server);
00260                         return _connect_auth_server(level);
00261                 }
00262                 else {
00263                         /*
00264                          * No
00265                          *
00266                          * It's probably safe to assume that the internet connection is malfunctioning
00267                          * and nothing we can do will make it work
00268                          */
00269                         mark_offline();
00270                         debug(LOG_DEBUG, "Level %d: Failed to resolve auth server and all popular servers. The internet connection is probably down", level);
00271                         return(-1);
00272                 }
00273         }
00274         else {
00275                 /*
00276                  * DNS resolving was successful
00277                  */
00278                 ip = safe_strdup(inet_ntoa(*h_addr));
00279                 debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] succeeded = [%s]", level, hostname, ip);
00280 
00281                 if (!auth_server->last_ip || strcmp(auth_server->last_ip, ip) != 0) {
00282                         /*
00283                          * But the IP address is different from the last one we knew
00284                          * Update it
00285                          */
00286                         debug(LOG_DEBUG, "Level %d: Updating last_ip IP of server [%s] to [%s]", level, hostname, ip);
00287                         if (auth_server->last_ip) free(auth_server->last_ip);
00288                         auth_server->last_ip = ip;
00289 
00290                         /* Update firewall rules */
00291                         fw_clear_authservers();
00292                         fw_set_authservers();
00293                 }
00294                 else {
00295                         /*
00296                          * IP is the same as last time
00297                          */
00298                         free(ip);
00299                 }
00300 
00301                 /*
00302                  * Connect to it
00303                  */
00304                 debug(LOG_DEBUG, "Level %d: Connecting to auth server %s:%d", level, hostname, auth_server->authserv_http_port);
00305                 their_addr.sin_family = AF_INET;
00306                 their_addr.sin_port = htons(auth_server->authserv_http_port);
00307                 their_addr.sin_addr = *h_addr;
00308                 memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero));
00309                 free (h_addr);
00310 
00311                 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
00312                         debug(LOG_ERR, "Level %d: Failed to create a new SOCK_STREAM socket: %s", strerror(errno));
00313                         return(-1);
00314                 }
00315 
00316                 if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
00317                         /*
00318                          * Failed to connect
00319                          * Mark the server as bad and try the next one
00320                          */
00321                         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));
00322                         close(sockfd);
00323                         mark_auth_server_bad(auth_server);
00324                         return _connect_auth_server(level);
00325                 }
00326                 else {
00327                         /*
00328                          * We have successfully connected
00329                          */
00330                         debug(LOG_DEBUG, "Level %d: Successfully connected to auth server %s:%d", level, hostname, auth_server->authserv_http_port);
00331                         return sockfd;
00332                 }
00333         }
00334 }
00335 
00336 /* config->authserv_maxtries */

Generated on Thu Sep 8 23:40:57 2005 for WifiDog by  doxygen 1.4.2