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

Generated on Sat Jan 6 18:51:43 2007 for WifiDog by  doxygen 1.5.1