centralserver.c

Go to the documentation of this file.
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 /* $Id: centralserver.c 1305 2007-11-01 20:04:20Z benoitg $ */
00027 #include <pthread.h>
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <sys/types.h>
00031 #include <sys/socket.h>
00032 #include <sys/stat.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 #include <errno.h>
00036 #include <unistd.h>
00037 #include <string.h>
00038 #include <syslog.h>
00039 
00040 #include "httpd.h"
00041 
00042 #include "common.h"
00043 #include "safe.h"
00044 #include "util.h"
00045 #include "auth.h"
00046 #include "conf.h"
00047 #include "debug.h"
00048 #include "centralserver.h"
00049 #include "firewall.h"
00050 #include "../config.h"
00051 
00052 extern pthread_mutex_t  config_mutex;
00053 
00064 t_authcode
00065 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)
00066 {
00067         int sockfd;
00068         size_t  numbytes, totalbytes;
00069         char buf[MAX_BUF];
00070         char *tmp;
00071         int done, nfds;
00072         fd_set                  readfds;
00073         struct timeval          timeout;
00074         t_auth_serv     *auth_server = NULL;
00075         auth_server = get_auth_server();
00076         
00077         /* Blanket default is error. */
00078         authresponse->authcode = AUTH_ERROR;
00079         
00080         sockfd = connect_auth_server();
00081         if (sockfd == -1) {
00082                 /* Could not connect to any auth server */
00083                 return (AUTH_ERROR);
00084         }
00085 
00090         memset(buf, 0, sizeof(buf));
00091         snprintf(buf, (sizeof(buf) - 1),
00092                 "GET %s%sstage=%s&ip=%s&mac=%s&token=%s&incoming=%llu&outgoing=%llu HTTP/1.0\r\n"
00093                 "User-Agent: WiFiDog %s\r\n"
00094                 "Host: %s\r\n"
00095                 "\r\n",
00096                 auth_server->authserv_path,
00097                 auth_server->authserv_auth_script_path_fragment,
00098                 request_type,
00099                 ip,
00100                 mac,
00101                 token,
00102                 incoming,
00103                 outgoing,
00104                 VERSION,
00105                 auth_server->authserv_hostname
00106         );
00107 
00108         debug(LOG_DEBUG, "Sending HTTP request to auth server: [%s]\n", buf);
00109         send(sockfd, buf, strlen(buf), 0);
00110 
00111         debug(LOG_DEBUG, "Reading response");
00112         numbytes = totalbytes = 0;
00113         done = 0;
00114         do {
00115                 FD_ZERO(&readfds);
00116                 FD_SET(sockfd, &readfds);
00117                 timeout.tv_sec = 30; /* XXX magic... 30 second is as good a timeout as any */
00118                 timeout.tv_usec = 0;
00119                 nfds = sockfd + 1;
00120 
00121                 nfds = select(nfds, &readfds, NULL, NULL, &timeout);
00122 
00123                 if (nfds > 0) {
00126                         numbytes = read(sockfd, buf + totalbytes, MAX_BUF - (totalbytes + 1));
00127                         if (numbytes < 0) {
00128                                 debug(LOG_ERR, "An error occurred while reading from auth server: %s", strerror(errno));
00129                                 /* FIXME */
00130                                 close(sockfd);
00131                                 return (AUTH_ERROR);
00132                         }
00133                         else if (numbytes == 0) {
00134                                 done = 1;
00135                         }
00136                         else {
00137                                 totalbytes += numbytes;
00138                                 debug(LOG_DEBUG, "Read %d bytes, total now %d", numbytes, totalbytes);
00139                         }
00140                 }
00141                 else if (nfds == 0) {
00142                         debug(LOG_ERR, "Timed out reading data via select() from auth server");
00143                         /* FIXME */
00144                         close(sockfd);
00145                         return (AUTH_ERROR);
00146                 }
00147                 else if (nfds < 0) {
00148                         debug(LOG_ERR, "Error reading data via select() from auth server: %s", strerror(errno));
00149                         /* FIXME */
00150                         close(sockfd);
00151                         return (AUTH_ERROR);
00152                 }
00153         } while (!done);
00154 
00155         close(sockfd);
00156 
00157         buf[totalbytes] = '\0';
00158         debug(LOG_DEBUG, "HTTP Response from Server: [%s]", buf);
00159         
00160         if ((tmp = strstr(buf, "Auth: "))) {
00161                 if (sscanf(tmp, "Auth: %d", (int *)&authresponse->authcode) == 1) {
00162                         debug(LOG_INFO, "Auth server returned authentication code %d", authresponse->authcode);
00163                         return(authresponse->authcode);
00164                 } else {
00165                         debug(LOG_WARNING, "Auth server did not return expected authentication code");
00166                         return(AUTH_ERROR);
00167                 }
00168         }
00169         else {
00170                 return(AUTH_ERROR);
00171         }
00172 
00173         /* XXX Never reached because of the above if()/else pair. */
00174         return(AUTH_ERROR);
00175 }
00176 
00177 /* Tries really hard to connect to an auth server. Returns a file descriptor, -1 on error
00178  */
00179 int connect_auth_server() {
00180         int sockfd;
00181 
00182         LOCK_CONFIG();
00183         sockfd = _connect_auth_server(0);
00184         UNLOCK_CONFIG();
00185 
00186         if (sockfd == -1) {
00187                 debug(LOG_ERR, "Failed to connect to any of the auth servers");
00188                 mark_auth_offline();
00189         }
00190         else {
00191                 debug(LOG_DEBUG, "Connected to auth server");
00192                 mark_auth_online();
00193         }
00194         return (sockfd);
00195 }
00196 
00197 /* Helper function called by connect_auth_server() to do the actual work including recursion
00198  * DO NOT CALL DIRECTLY
00199  @param level recursion level indicator must be 0 when not called by _connect_auth_server()
00200  */
00201 int _connect_auth_server(int level) {
00202         s_config *config = config_get_config();
00203         t_auth_serv *auth_server = NULL;
00204         struct in_addr *h_addr;
00205         int num_servers = 0;
00206         char * hostname = NULL;
00207         char * popular_servers[] = {
00208                   "www.google.com",
00209                   "www.yahoo.com",
00210                   NULL
00211         };
00212         char ** popularserver;
00213         char * ip;
00214         struct sockaddr_in their_addr;
00215         int sockfd;
00216 
00217         /* XXX level starts out at 0 and gets incremented by every iterations. */
00218         level++;
00219 
00220         /*
00221          * Let's calculate the number of servers we have
00222          */
00223         for (auth_server = config->auth_servers; auth_server; auth_server = auth_server->next) {
00224                 num_servers++;
00225         }
00226         debug(LOG_DEBUG, "Level %d: Calculated %d auth servers in list", level, num_servers);
00227 
00228         if (level > num_servers) {
00229                 /*
00230                  * We've called ourselves too many times
00231                  * This means we've cycled through all the servers in the server list
00232                  * at least once and none are accessible
00233                  */
00234                 return (-1);
00235         }
00236 
00237         /*
00238          * Let's resolve the hostname of the top server to an IP address
00239          */
00240         auth_server = config->auth_servers;
00241         hostname = auth_server->authserv_hostname;
00242         debug(LOG_DEBUG, "Level %d: Resolving auth server [%s]", level, hostname);
00243         h_addr = wd_gethostbyname(hostname);
00244         if (!h_addr) {
00245                 /*
00246                  * DNS resolving it failed
00247                  *
00248                  * Can we resolve any of the popular servers ?
00249                  */
00250                 debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] failed", level, hostname);
00251 
00252                 for (popularserver = popular_servers; *popularserver; popularserver++) {
00253                         debug(LOG_DEBUG, "Level %d: Resolving popular server [%s]", level, *popularserver);
00254                         h_addr = wd_gethostbyname(*popularserver);
00255                         if (h_addr) {
00256                                 debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] succeeded = [%s]", level, *popularserver, inet_ntoa(*h_addr));
00257                                 break;
00258                         }
00259                         else {
00260                                 debug(LOG_DEBUG, "Level %d: Resolving popular server [%s] failed", level, *popularserver);
00261                         }
00262                 }
00263 
00264                 /* 
00265                  * If we got any h_addr buffer for one of the popular servers, in other
00266                  * words, if one of the popular servers resolved, we'll assume the DNS
00267                  * works, otherwise we'll deal with net connection or DNS failure.
00268                  */
00269                 if (h_addr) {
00270                         free (h_addr);
00271                         /*
00272                          * Yes
00273                          *
00274                          * The auth server's DNS server is probably dead. Try the next auth server
00275                          */
00276                         debug(LOG_DEBUG, "Level %d: Marking auth server [%s] as bad and trying next if possible", level, hostname);
00277                         if (auth_server->last_ip) {
00278                                 free(auth_server->last_ip);
00279                                 auth_server->last_ip = NULL;
00280                         }
00281                         mark_auth_server_bad(auth_server);
00282                         return _connect_auth_server(level);
00283                 }
00284                 else {
00285                         /*
00286                          * No
00287                          *
00288                          * It's probably safe to assume that the internet connection is malfunctioning
00289                          * and nothing we can do will make it work
00290                          */
00291                         mark_offline();
00292                         debug(LOG_DEBUG, "Level %d: Failed to resolve auth server and all popular servers. "
00293                                         "The internet connection is probably down", level);
00294                         return(-1);
00295                 }
00296         }
00297         else {
00298                 /*
00299                  * DNS resolving was successful
00300                  */
00301                 ip = safe_strdup(inet_ntoa(*h_addr));
00302                 debug(LOG_DEBUG, "Level %d: Resolving auth server [%s] succeeded = [%s]", level, hostname, ip);
00303 
00304                 if (!auth_server->last_ip || strcmp(auth_server->last_ip, ip) != 0) {
00305                         /*
00306                          * But the IP address is different from the last one we knew
00307                          * Update it
00308                          */
00309                         debug(LOG_DEBUG, "Level %d: Updating last_ip IP of server [%s] to [%s]", level, hostname, ip);
00310                         if (auth_server->last_ip) free(auth_server->last_ip);
00311                         auth_server->last_ip = ip;
00312 
00313                         /* Update firewall rules */
00314                         fw_clear_authservers();
00315                         fw_set_authservers();
00316                 }
00317                 else {
00318                         /*
00319                          * IP is the same as last time
00320                          */
00321                         free(ip);
00322                 }
00323 
00324                 /*
00325                  * Connect to it
00326                  */
00327                 debug(LOG_DEBUG, "Level %d: Connecting to auth server %s:%d", level, hostname, auth_server->authserv_http_port);
00328                 their_addr.sin_family = AF_INET;
00329                 their_addr.sin_port = htons(auth_server->authserv_http_port);
00330                 their_addr.sin_addr = *h_addr;
00331                 memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero));
00332                 free (h_addr);
00333 
00334                 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
00335                         debug(LOG_ERR, "Level %d: Failed to create a new SOCK_STREAM socket: %s", strerror(errno));
00336                         return(-1);
00337                 }
00338 
00339                 if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
00340                         /*
00341                          * Failed to connect
00342                          * Mark the server as bad and try the next one
00343                          */
00344                         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));
00345                         close(sockfd);
00346                         mark_auth_server_bad(auth_server);
00347                         return _connect_auth_server(level); /* Yay recursion! */
00348                 }
00349                 else {
00350                         /*
00351                          * We have successfully connected
00352                          */
00353                         debug(LOG_DEBUG, "Level %d: Successfully connected to auth server %s:%d", level, hostname, auth_server->authserv_http_port);
00354                         return sockfd;
00355                 }
00356         }
00357 }

Generated on Sun Apr 13 21:55:00 2008 for WifiDog by  doxygen 1.5.3