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