00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <syslog.h>
00032 #include <pthread.h>
00033 #include <signal.h>
00034 #include <errno.h>
00035 #include <time.h>
00036
00037
00038 #include <string.h>
00039
00040
00041 #include <sys/wait.h>
00042
00043
00044 #include <sys/socket.h>
00045 #include <sys/un.h>
00046
00047 #include "common.h"
00048 #include "httpd.h"
00049 #include "safe.h"
00050 #include "debug.h"
00051 #include "conf.h"
00052 #include "gateway.h"
00053 #include "firewall.h"
00054 #include "commandline.h"
00055 #include "auth.h"
00056 #include "http.h"
00057 #include "client_list.h"
00058 #include "wdctl_thread.h"
00059 #include "ping_thread.h"
00060 #include "httpd_thread.h"
00061 #include "util.h"
00062
00067 static pthread_t tid_fw_counter = 0;
00068 static pthread_t tid_ping = 0;
00069
00070
00071 httpd * webserver = NULL;
00072
00073
00074 extern char ** restartargv;
00075 extern pid_t restart_orig_pid;
00076 t_client *firstclient;
00077
00078
00079 extern pthread_mutex_t client_list_mutex;
00080
00081
00082 time_t started_time = 0;
00083
00084
00085
00086
00087
00088
00089
00090 void append_x_restartargv(void) {
00091 int i;
00092
00093 for (i=0; restartargv[i]; i++);
00094
00095 restartargv[i++] = safe_strdup("-x");
00096 safe_asprintf(&(restartargv[i++]), "%d", getpid());
00097 }
00098
00099
00100
00101
00102
00103 void get_clients_from_parent(void) {
00104 int sock;
00105 struct sockaddr_un sa_un;
00106 s_config * config = NULL;
00107 char linebuffer[MAX_BUF];
00108 int len = 0;
00109 char *running1 = NULL;
00110 char *running2 = NULL;
00111 char *token1 = NULL;
00112 char *token2 = NULL;
00113 char onechar;
00114 char *command = NULL;
00115 char *key = NULL;
00116 char *value = NULL;
00117 t_client * client = NULL;
00118 t_client * lastclient = NULL;
00119
00120 config = config_get_config();
00121
00122 debug(LOG_INFO, "Connecting to parent to download clients");
00123
00124
00125 sock = socket(AF_UNIX, SOCK_STREAM, 0);
00126 memset(&sa_un, 0, sizeof(sa_un));
00127 sa_un.sun_family = AF_UNIX;
00128 strncpy(sa_un.sun_path, config->internal_sock, (sizeof(sa_un.sun_path) - 1));
00129
00130 if (connect(sock, (struct sockaddr *)&sa_un, strlen(sa_un.sun_path) + sizeof(sa_un.sun_family))) {
00131 debug(LOG_ERR, "Failed to connect to parent (%s) - client list not downloaded", strerror(errno));
00132 return;
00133 }
00134
00135 debug(LOG_INFO, "Connected to parent. Downloading clients");
00136
00137 LOCK_CLIENT_LIST();
00138
00139 command = NULL;
00140 memset(linebuffer, 0, sizeof(linebuffer));
00141 len = 0;
00142 client = NULL;
00143
00144 while (read(sock, &onechar, 1) == 1) {
00145 if (onechar == '\n') {
00146
00147 onechar = '\0';
00148 }
00149 linebuffer[len++] = onechar;
00150
00151 if (!onechar) {
00152
00153 debug(LOG_DEBUG, "Received from parent: [%s]", linebuffer);
00154 running1 = linebuffer;
00155 while ((token1 = strsep(&running1, "|")) != NULL) {
00156 if (!command) {
00157
00158 command = token1;
00159 }
00160 else {
00161
00162 running2 = token1;
00163 key = value = NULL;
00164 while ((token2 = strsep(&running2, "=")) != NULL) {
00165 if (!key) {
00166 key = token2;
00167 }
00168 else if (!value) {
00169 value = token2;
00170 }
00171 }
00172 }
00173
00174 if (strcmp(command, "CLIENT") == 0) {
00175
00176 if (!client) {
00177
00178 client = safe_malloc(sizeof(t_client));
00179 memset(client, 0, sizeof(t_client));
00180 }
00181 }
00182
00183 if (key && value) {
00184 if (strcmp(command, "CLIENT") == 0) {
00185
00186 if (strcmp(key, "ip") == 0) {
00187 client->ip = safe_strdup(value);
00188 }
00189 else if (strcmp(key, "mac") == 0) {
00190 client->mac = safe_strdup(value);
00191 }
00192 else if (strcmp(key, "token") == 0) {
00193 client->token = safe_strdup(value);
00194 }
00195 else if (strcmp(key, "fw_connection_state") == 0) {
00196 client->fw_connection_state = atoi(value);
00197 }
00198 else if (strcmp(key, "fd") == 0) {
00199 client->fd = atoi(value);
00200 }
00201 else if (strcmp(key, "counters_incoming") == 0) {
00202 client->counters.incoming_history = atoll(value);
00203 client->counters.incoming = client->counters.incoming_history;
00204 }
00205 else if (strcmp(key, "counters_outgoing") == 0) {
00206 client->counters.outgoing_history = atoll(value);
00207 client->counters.outgoing = client->counters.outgoing_history;
00208 }
00209 else if (strcmp(key, "counters_last_updated") == 0) {
00210 client->counters.last_updated = atol(value);
00211 }
00212 else {
00213 debug(LOG_NOTICE, "I don't know how to inherit key [%s] value [%s] from parent", key, value);
00214 }
00215 }
00216 }
00217 }
00218
00219
00220 if (client) {
00221
00222 if (!firstclient) {
00223 firstclient = client;
00224 lastclient = firstclient;
00225 }
00226 else {
00227 lastclient->next = client;
00228 lastclient = client;
00229 }
00230 }
00231
00232
00233 command = NULL;
00234 memset(linebuffer, 0, sizeof(linebuffer));
00235 len = 0;
00236 client = NULL;
00237 }
00238 }
00239
00240 UNLOCK_CLIENT_LIST();
00241 debug(LOG_INFO, "Client list downloaded successfully from parent");
00242
00243 close(sock);
00244 }
00245
00253 void
00254 sigchld_handler(int s)
00255 {
00256 int status;
00257 pid_t rc;
00258
00259 debug(LOG_DEBUG, "Handler for SIGCHLD called. Trying to reap a child");
00260
00261 rc = waitpid(-1, &status, WNOHANG);
00262
00263 debug(LOG_DEBUG, "Handler for SIGCHLD reaped child PID %d", rc);
00264 }
00265
00268 void
00269 termination_handler(int s)
00270 {
00271 static pthread_mutex_t sigterm_mutex = PTHREAD_MUTEX_INITIALIZER;
00272 s_config *config = config_get_config();
00273
00274 debug(LOG_INFO, "Handler for termination caught signal %d", s);
00275
00276
00277 if (pthread_mutex_trylock(&sigterm_mutex)) {
00278 debug(LOG_INFO, "Another thread already began global termination handler. I'm exiting");
00279 pthread_exit(NULL);
00280 }
00281 else {
00282 debug(LOG_INFO, "Cleaning up and exiting");
00283 }
00284
00285 debug(LOG_INFO, "Flushing firewall rules...");
00286 fw_destroy();
00287
00288
00289
00290
00291
00292
00293 if (tid_fw_counter) {
00294 debug(LOG_INFO, "Explicitly killing the fw_counter thread");
00295 pthread_kill(tid_fw_counter, SIGKILL);
00296 }
00297 if (tid_ping) {
00298 debug(LOG_INFO, "Explicitly killing the ping thread");
00299 pthread_kill(tid_ping, SIGKILL);
00300 }
00301
00302 debug(LOG_NOTICE, "Exiting...");
00303 exit(s == 0 ? 1 : 0);
00304 }
00305
00309 static void
00310 init_signals(void)
00311 {
00312 struct sigaction sa;
00313
00314 debug(LOG_DEBUG, "Initializing signal handlers");
00315
00316 sa.sa_handler = sigchld_handler;
00317 sigemptyset(&sa.sa_mask);
00318 sa.sa_flags = SA_RESTART;
00319 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
00320 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00321 exit(1);
00322 }
00323
00324
00325
00326
00327
00328
00329
00330 sa.sa_handler = SIG_IGN;
00331 if (sigaction(SIGPIPE, &sa, NULL) == -1) {
00332 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00333 exit(1);
00334 }
00335
00336 sa.sa_handler = termination_handler;
00337 sigemptyset(&sa.sa_mask);
00338 sa.sa_flags = SA_RESTART;
00339
00340
00341 if (sigaction(SIGTERM, &sa, NULL) == -1) {
00342 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00343 exit(1);
00344 }
00345
00346
00347 if (sigaction(SIGQUIT, &sa, NULL) == -1) {
00348 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00349 exit(1);
00350 }
00351
00352
00353 if (sigaction(SIGINT, &sa, NULL) == -1) {
00354 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00355 exit(1);
00356 }
00357 }
00358
00362 static void
00363 main_loop(void)
00364 {
00365 int result;
00366 pthread_t tid;
00367 s_config *config = config_get_config();
00368 request *r;
00369 void **params;
00370 FILE *fh;
00371
00372
00373 if (!started_time) {
00374 debug(LOG_INFO, "Setting started_time");
00375 started_time = time(NULL);
00376 }
00377 else if (started_time < MINIMUM_STARTED_TIME) {
00378 debug(LOG_WARNING, "Detected possible clock skew - re-setting started_time");
00379 started_time = time(NULL);
00380 }
00381
00382
00383 if (!config->gw_address) {
00384 debug(LOG_DEBUG, "Finding IP address of %s", config->gw_interface);
00385 if ((config->gw_address = get_iface_ip(config->gw_interface)) == NULL) {
00386 debug(LOG_ERR, "Could not get IP address information of %s, exiting...", config->gw_interface);
00387 exit(1);
00388 }
00389 debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_address);
00390 }
00391
00392
00393
00394 if (!config->gw_id) {
00395 debug(LOG_DEBUG, "Finding MAC address of %s", config->gw_interface);
00396 if ((config->gw_id = get_iface_mac(config->gw_interface)) == NULL) {
00397 debug(LOG_ERR, "Could not get MAC address information of %s, exiting...", config->gw_interface);
00398 exit(1);
00399 }
00400 debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_id);
00401 }
00402
00403
00404 debug(LOG_NOTICE, "Creating web server on %s:%d", config->gw_address, config->gw_port);
00405 if ((webserver = httpdCreate(config->gw_address, config->gw_port)) == NULL) {
00406 debug(LOG_ERR, "Could not create web server: %s", strerror(errno));
00407 exit(1);
00408 }
00409
00410 debug(LOG_DEBUG, "Assigning callbacks to web server");
00411 httpdAddCContent(webserver, "/", "wifidog", 0, NULL, http_callback_wifidog);
00412 httpdAddCContent(webserver, "/wifidog", "", 0, NULL, http_callback_wifidog);
00413 httpdAddCContent(webserver, "/wifidog", "about", 0, NULL, http_callback_about);
00414 httpdAddCContent(webserver, "/wifidog", "status", 0, NULL, http_callback_status);
00415 httpdAddCContent(webserver, "/wifidog", "auth", 0, NULL, http_callback_auth);
00416
00417 httpdAddC404Content(webserver, http_callback_404);
00418
00419
00420 fw_destroy();
00421
00422 fw_init();
00423
00424
00425 result = pthread_create(&tid_fw_counter, NULL, (void *)thread_client_timeout_check, NULL);
00426 if (result != 0) {
00427 debug(LOG_ERR, "FATAL: Failed to create a new thread (fw_counter) - exiting");
00428 termination_handler(0);
00429 }
00430 pthread_detach(tid_fw_counter);
00431
00432
00433 result = pthread_create(&tid, NULL, (void *)thread_wdctl, (void *)safe_strdup(config->wdctl_sock));
00434 if (result != 0) {
00435 debug(LOG_ERR, "FATAL: Failed to create a new thread (wdctl) - exiting");
00436 termination_handler(0);
00437 }
00438 pthread_detach(tid);
00439
00440
00441 result = pthread_create(&tid_ping, NULL, (void *)thread_ping, NULL);
00442 if (result != 0) {
00443 debug(LOG_ERR, "FATAL: Failed to create a new thread (ping) - exiting");
00444 termination_handler(0);
00445 }
00446 pthread_detach(tid_ping);
00447
00448 debug(LOG_NOTICE, "Waiting for connections");
00449 while(1) {
00450 r = httpdGetConnection(webserver, NULL);
00451
00452
00453
00454 if (webserver->lastError == -1) {
00455
00456 continue;
00457 }
00458 else if (webserver->lastError < -1) {
00459
00460
00461
00462
00463
00464 debug(LOG_ERR, "FATAL: httpdGetConnection returned unexpected value %d, exiting.", webserver->lastError);
00465 termination_handler(0);
00466 }
00467 else if (r != NULL) {
00468
00469
00470
00471
00472
00473 debug(LOG_INFO, "Received connection from %s, spawning worker thread", r->clientAddr);
00474
00475
00476 params = safe_malloc(2 * sizeof(void *));
00477 *params = webserver;
00478 *(params + 1) = r;
00479
00480 result = pthread_create(&tid, NULL, (void *)thread_httpd, (void *)params);
00481 if (result != 0) {
00482 debug(LOG_ERR, "FATAL: Failed to create a new thread (httpd) - exiting");
00483 termination_handler(0);
00484 }
00485 pthread_detach(tid);
00486 }
00487 else {
00488
00489
00490
00491 }
00492 }
00493
00494
00495 }
00496
00498 int main(int argc, char **argv) {
00499
00500 s_config *config = config_get_config();
00501 config_init();
00502
00503 parse_commandline(argc, argv);
00504
00505
00506 config_read(config->configfile);
00507 config_validate();
00508
00509
00510 client_list_init();
00511
00512
00513 init_signals();
00514
00515 if (restart_orig_pid) {
00516
00517
00518
00519 get_clients_from_parent();
00520
00521
00522
00523
00524 while (kill(restart_orig_pid, 0) != -1) {
00525 debug(LOG_INFO, "Waiting for parent PID %d to die before continuing loading", restart_orig_pid);
00526 sleep(1);
00527 }
00528
00529 debug(LOG_INFO, "Parent PID %d seems to be dead. Continuing loading.");
00530 }
00531
00532 if (config->daemon) {
00533
00534 debug(LOG_INFO, "Forking into background");
00535
00536 switch(safe_fork()) {
00537 case 0:
00538 setsid();
00539 append_x_restartargv();
00540 main_loop();
00541 break;
00542
00543 default:
00544 exit(0);
00545 break;
00546 }
00547 }
00548 else {
00549 append_x_restartargv();
00550 main_loop();
00551 }
00552
00553 return(0);
00554 }