util.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 /*
00022  * $Id: util.c 1243 2007-06-28 01:48:01Z benoitg $
00023  */
00031 #define _GNU_SOURCE
00032 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <syslog.h>
00036 #include <errno.h>
00037 #include <pthread.h>
00038 #include <sys/wait.h>
00039 #include <sys/types.h>
00040 #include <sys/unistd.h>
00041 #include <netinet/in.h>
00042 #include <sys/ioctl.h>
00043 
00044 #ifdef __linux__
00045 #include <net/if.h>
00046 #endif
00047 
00048 #include <string.h>
00049 #include <pthread.h>
00050 #include <netdb.h>
00051 
00052 #include "common.h"
00053 #include "client_list.h"
00054 #include "safe.h"
00055 #include "util.h"
00056 #include "conf.h"
00057 #include "debug.h"
00058 
00059 #include "../config.h"
00060 
00061 static pthread_mutex_t ghbn_mutex = PTHREAD_MUTEX_INITIALIZER;
00062 
00063 /* Defined in ping_thread.c */
00064 extern time_t started_time;
00065 
00066 /* Defined in clientlist.c */
00067 extern  pthread_mutex_t client_list_mutex;
00068 extern  pthread_mutex_t config_mutex;
00069 
00070 /* Defined in commandline.c */
00071 extern pid_t restart_orig_pid;
00072 
00073 /* XXX Do these need to be locked ? */
00074 static time_t last_online_time = 0;
00075 static time_t last_offline_time = 0;
00076 static time_t last_auth_online_time = 0;
00077 static time_t last_auth_offline_time = 0;
00078 
00079 long served_this_session = 0;
00080 
00086 int
00087 execute(char *cmd_line, int quiet)
00088 {
00089     int pid,
00090         status,
00091         rc;
00092 
00093     const char *new_argv[4];
00094     new_argv[0] = "/bin/sh";
00095     new_argv[1] = "-c";
00096     new_argv[2] = cmd_line;
00097     new_argv[3] = NULL;
00098 
00099          pid = safe_fork();
00100          if (pid == 0) {    /* for the child process:         */
00101         /* We don't want to see any errors if quiet flag is on */
00102         if (quiet) close(2);
00103         if (execvp("/bin/sh", (char *const *)new_argv) < 0) {    /* execute the command  */
00104             debug(LOG_ERR, "execvp(): %s", strerror(errno));
00105             exit(1);
00106         }
00107     }
00108          else {        /* for the parent:      */
00109                 debug(LOG_DEBUG, "Waiting for PID %d to exit", pid);
00110                 rc = waitpid(pid, &status, 0);
00111                 debug(LOG_DEBUG, "Process PID %d exited", rc);
00112     }
00113 
00114     return (WEXITSTATUS(status));
00115 }
00116 
00117 struct in_addr *
00118 wd_gethostbyname(const char *name)
00119 {
00120         struct hostent *he;
00121         struct in_addr *h_addr, *in_addr_temp;
00122 
00123         /* XXX Calling function is reponsible for free() */
00124 
00125         h_addr = safe_malloc(sizeof(struct in_addr));
00126         
00127         LOCK_GHBN();
00128 
00129         he = gethostbyname(name);
00130 
00131         if (he == NULL) {
00132                 free(h_addr);
00133                 UNLOCK_GHBN();
00134                 return NULL;
00135         }
00136 
00137         mark_online();
00138 
00139         in_addr_temp = (struct in_addr *)he->h_addr_list[0];
00140         h_addr->s_addr = in_addr_temp->s_addr;
00141         
00142         UNLOCK_GHBN();
00143 
00144         return h_addr;
00145 }
00146 
00147 char *get_iface_ip(char *ifname) {
00148 #ifdef __linux__
00149     struct ifreq if_data;
00150 #endif
00151     struct in_addr in;
00152     char *ip_str;
00153     int sockd;
00154     u_int32_t ip;
00155 
00156 #ifdef __linux__
00157     
00158     /* Create a socket */
00159     if ((sockd = socket (AF_INET, SOCK_PACKET, htons(0x8086))) < 0) {
00160         debug(LOG_ERR, "socket(): %s", strerror(errno));
00161         return NULL;
00162     }
00163 
00164     /* Get IP of internal interface */
00165     strcpy (if_data.ifr_name, ifname);
00166 
00167     /* Get the IP address */
00168     if (ioctl (sockd, SIOCGIFADDR, &if_data) < 0) {
00169         debug(LOG_ERR, "ioctl(): SIOCGIFADDR %s", strerror(errno));
00170         return NULL;
00171     }
00172     memcpy ((void *) &ip, (void *) &if_data.ifr_addr.sa_data + 2, 4);
00173     in.s_addr = ip;
00174 
00175     ip_str = (char *)inet_ntoa(in);
00176     close(sockd);
00177     return safe_strdup(ip_str);
00178 #else
00179     return safe_strdup("0.0.0.0");
00180 #endif
00181 }
00182 
00183 char *get_iface_mac (char *ifname) {
00184 #ifdef __linux__
00185     int r, s;
00186     struct ifreq ifr;
00187     char *hwaddr, mac[13];
00188     
00189     strcpy(ifr.ifr_name, ifname);
00190 
00191     s = socket(PF_INET, SOCK_DGRAM, 0);
00192     if (-1 == s) {
00193        debug(LOG_ERR, "get_iface_mac socket: %s", strerror(errno));
00194        return NULL;
00195     }
00196 
00197     r = ioctl(s, SIOCGIFHWADDR, &ifr);
00198     if (r == -1) {
00199        debug(LOG_ERR, "get_iface_mac ioctl(SIOCGIFHWADDR): %s", strerror(errno));
00200        close(s);
00201        return NULL;
00202     }
00203 
00204     hwaddr = ifr.ifr_hwaddr.sa_data;
00205     snprintf(mac, 13, "%02X%02X%02X%02X%02X%02X", 
00206        hwaddr[0] & 0xFF,
00207        hwaddr[1] & 0xFF,
00208        hwaddr[2] & 0xFF,
00209        hwaddr[3] & 0xFF,
00210        hwaddr[4] & 0xFF,
00211        hwaddr[5] & 0xFF
00212        );
00213        
00214     close(s);
00215     return safe_strdup(mac);
00216 #else
00217     return NULL;
00218 #endif
00219 }
00220 
00221 char *get_ext_iface (void) {
00222 #ifdef __linux__
00223     FILE *input;
00224     char *device, *gw;
00225     int i = 1;
00226     int keep_detecting = 1;
00227     pthread_cond_t              cond = PTHREAD_COND_INITIALIZER;
00228     pthread_mutex_t             cond_mutex = PTHREAD_MUTEX_INITIALIZER;
00229     struct      timespec        timeout;
00230     device = (char *)malloc(16);
00231     gw = (char *)malloc(16);
00232     debug(LOG_DEBUG, "get_ext_iface(): Autodectecting the external interface from routing table");
00233     while(keep_detecting) {
00234         input = fopen("/proc/net/route", "r");
00235         while (!feof(input)) {
00236             fscanf(input, "%s %s %*s %*s %*s %*s %*s %*s %*s %*s %*s\n", device, gw);
00237             if (strcmp(gw, "00000000") == 0) {
00238                 free(gw);
00239                 debug(LOG_INFO, "get_ext_iface(): Detected %s as the default interface after try %d", device, i);
00240                 return device;
00241             }
00242         }
00243         fclose(input);
00244         debug(LOG_ERR, "get_ext_iface(): Failed to detect the external interface after try %d (maybe the interface is not up yet?).  Retry limit: %d", i, NUM_EXT_INTERFACE_DETECT_RETRY);
00245         /* Sleep for EXT_INTERFACE_DETECT_RETRY_INTERVAL seconds */
00246         timeout.tv_sec = time(NULL) + EXT_INTERFACE_DETECT_RETRY_INTERVAL;
00247         timeout.tv_nsec = 0;
00248         /* Mutex must be locked for pthread_cond_timedwait... */
00249         pthread_mutex_lock(&cond_mutex);        
00250         /* Thread safe "sleep" */
00251         pthread_cond_timedwait(&cond, &cond_mutex, &timeout);
00252         /* No longer needs to be locked */
00253         pthread_mutex_unlock(&cond_mutex);
00254             //for (i=1; i<=NUM_EXT_INTERFACE_DETECT_RETRY; i++) {
00255             if (NUM_EXT_INTERFACE_DETECT_RETRY != 0 && i>NUM_EXT_INTERFACE_DETECT_RETRY) {
00256                 keep_detecting = 0;
00257             }
00258             i++;
00259     }
00260     debug(LOG_ERR, "get_ext_iface(): Failed to detect the external interface after %d tries, aborting", i);
00261     exit(1);
00262     free(device);
00263     free(gw);
00264 #endif
00265     return NULL;
00266 }
00267 
00268 void mark_online() {
00269         int before;
00270         int after;
00271 
00272         before = is_online();
00273         time(&last_online_time);
00274         after = is_online();
00275 
00276         if (before != after) {
00277                 debug(LOG_INFO, "ONLINE status became %s", (after ? "ON" : "OFF"));
00278         }
00279 
00280 }
00281 
00282 void mark_offline() {
00283         int before;
00284         int after;
00285 
00286         before = is_online();
00287         time(&last_offline_time);
00288         after = is_online();
00289 
00290         if (before != after) {
00291                 debug(LOG_INFO, "ONLINE status became %s", (after ? "ON" : "OFF"));
00292         }
00293 
00294         /* If we're offline it definately means the auth server is offline */
00295         mark_auth_offline();
00296 
00297 }
00298 
00299 int is_online() {
00300         if (last_online_time == 0 || (last_offline_time - last_online_time) >= (config_get_config()->checkinterval * 2) ) {
00301                 /* We're probably offline */
00302                 return (0);
00303         }
00304         else {
00305                 /* We're probably online */
00306                 return (1);
00307         }
00308 }
00309 
00310 void mark_auth_online() {
00311         int before;
00312         int after;
00313 
00314         before = is_auth_online();
00315         time(&last_auth_online_time);
00316         after = is_auth_online();
00317 
00318         if (before != after) {
00319                 debug(LOG_INFO, "AUTH_ONLINE status became %s", (after ? "ON" : "OFF"));
00320         }
00321 
00322         /* If auth server is online it means we're definately online */
00323         mark_online();
00324 
00325 }
00326 
00327 void mark_auth_offline() {
00328         int before;
00329         int after;
00330 
00331         before = is_auth_online();
00332         time(&last_auth_offline_time);
00333         after = is_auth_online();
00334 
00335         if (before != after) {
00336                 debug(LOG_INFO, "AUTH_ONLINE status became %s", (after ? "ON" : "OFF"));
00337         }
00338 
00339 }
00340 
00341 int is_auth_online() {
00342         if (!is_online()) {
00343                 /* If we're not online auth is definately not online :) */
00344                 return (0);
00345         }
00346         else if (last_auth_online_time == 0 || (last_auth_offline_time - last_auth_online_time) >= (config_get_config()->checkinterval * 2) ) {
00347                 /* Auth is  probably offline */
00348                 return (0);
00349         }
00350         else {
00351                 /* Auth is probably online */
00352                 return (1);
00353         }
00354 }
00355 
00356 /*
00357  * @return A string containing human-readable status text. MUST BE free()d by caller
00358  */
00359 char * get_status_text() {
00360         char buffer[STATUS_BUF_SIZ];
00361         ssize_t len;
00362         s_config *config;
00363         t_auth_serv *auth_server;
00364         t_client        *first;
00365         int             count;
00366         unsigned long int uptime = 0;
00367         unsigned int days = 0, hours = 0, minutes = 0, seconds = 0;
00368      t_trusted_mac *p;
00369         
00370         len = 0;
00371         snprintf(buffer, (sizeof(buffer) - len), "WiFiDog status\n\n");
00372         len = strlen(buffer);
00373 
00374         uptime = time(NULL) - started_time;
00375         days    = uptime / (24 * 60 * 60);
00376         uptime -= days * (24 * 60 * 60);
00377         hours   = uptime / (60 * 60);
00378         uptime -= hours * (60 * 60);
00379         minutes = uptime / 60;
00380         uptime -= minutes * 60;
00381         seconds = uptime;
00382 
00383         snprintf((buffer + len), (sizeof(buffer) - len), "Version: " VERSION "\n");
00384         len = strlen(buffer);
00385 
00386         snprintf((buffer + len), (sizeof(buffer) - len), "Uptime: %ud %uh %um %us\n", days, hours, minutes, seconds);
00387         len = strlen(buffer);
00388 
00389         snprintf((buffer + len), (sizeof(buffer) - len), "Has been restarted: ");
00390         len = strlen(buffer);
00391         if (restart_orig_pid) {
00392                 snprintf((buffer + len), (sizeof(buffer) - len), "yes (from PID %d)\n", restart_orig_pid);
00393                 len = strlen(buffer);
00394         }
00395         else {
00396                 snprintf((buffer + len), (sizeof(buffer) - len), "no\n");
00397                 len = strlen(buffer);
00398         }
00399         
00400         snprintf((buffer + len), (sizeof(buffer) - len), "Internet Connectivity: %s\n", (is_online() ? "yes" : "no"));
00401         len = strlen(buffer);
00402         
00403         snprintf((buffer + len), (sizeof(buffer) - len), "Auth server reachable: %s\n", (is_auth_online() ? "yes" : "no"));
00404         len = strlen(buffer);
00405 
00406         snprintf((buffer + len), (sizeof(buffer) - len), "Clients served this session: %lu\n\n", served_this_session);
00407         len = strlen(buffer);
00408 
00409         LOCK_CLIENT_LIST();
00410         
00411         first = client_get_first_client();
00412         
00413         if (first == NULL) {
00414                 count = 0;
00415         } else {
00416                 count = 1;
00417                 while (first->next != NULL) {
00418                         first = first->next;
00419                         count++;
00420                 }
00421         }
00422         
00423         snprintf((buffer + len), (sizeof(buffer) - len), "%d clients "
00424                         "connected.\n", count);
00425         len = strlen(buffer);
00426 
00427         first = client_get_first_client();
00428 
00429         count = 0;
00430         while (first != NULL) {
00431                 snprintf((buffer + len), (sizeof(buffer) - len), "\nClient %d\n", count);
00432                 len = strlen(buffer);
00433 
00434                 snprintf((buffer + len), (sizeof(buffer) - len), "  IP: %s MAC: %s\n", first->ip, first->mac);
00435                 len = strlen(buffer);
00436 
00437                 snprintf((buffer + len), (sizeof(buffer) - len), "  Token: %s\n", first->token);
00438                 len = strlen(buffer);
00439 
00440                 snprintf((buffer + len), (sizeof(buffer) - len), "  Downloaded: %llu\n  Uploaded: %llu\n" , first->counters.incoming, first->counters.outgoing);
00441                 len = strlen(buffer);
00442 
00443                 count++;
00444                 first = first->next;
00445         }
00446 
00447         UNLOCK_CLIENT_LIST();
00448 
00449     config = config_get_config();
00450     
00451     if (config->trustedmaclist != NULL) {
00452         snprintf((buffer + len), (sizeof(buffer) - len), "\nTrusted MAC addresses:\n");
00453         len = strlen(buffer);
00454 
00455         for (p = config->trustedmaclist; p != NULL; p = p->next) {
00456             snprintf((buffer + len), (sizeof(buffer) - len), "  %s\n", p->mac);
00457             len = strlen(buffer);
00458         }
00459     }
00460 
00461     snprintf((buffer + len), (sizeof(buffer) - len), "\nAuthentication servers:\n");
00462     len = strlen(buffer);
00463 
00464     LOCK_CONFIG();
00465 
00466     for (auth_server = config->auth_servers; auth_server != NULL; auth_server = auth_server->next) {
00467         snprintf((buffer + len), (sizeof(buffer) - len), "  Host: %s (%s)\n", auth_server->authserv_hostname, auth_server->last_ip);
00468         len = strlen(buffer);
00469     }
00470 
00471     UNLOCK_CONFIG();
00472 
00473         return safe_strdup(buffer);
00474 }

Generated on Thu Oct 18 17:15:19 2007 for WifiDog by  doxygen 1.5.3