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

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