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