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
00273 debug(LOG_INFO, "Handler for termination caught signal %d", s);
00274
00275
00276 if (pthread_mutex_trylock(&sigterm_mutex)) {
00277 debug(LOG_INFO, "Another thread already began global termination handler. I'm exiting");
00278 pthread_exit(NULL);
00279 }
00280 else {
00281 debug(LOG_INFO, "Cleaning up and exiting");
00282 }
00283
00284 debug(LOG_INFO, "Flushing firewall rules...");
00285 fw_destroy();
00286
00287
00288
00289
00290
00291
00292 if (tid_fw_counter) {
00293 debug(LOG_INFO, "Explicitly killing the fw_counter thread");
00294 pthread_kill(tid_fw_counter, SIGKILL);
00295 }
00296 if (tid_ping) {
00297 debug(LOG_INFO, "Explicitly killing the ping thread");
00298 pthread_kill(tid_ping, SIGKILL);
00299 }
00300
00301 debug(LOG_NOTICE, "Exiting...");
00302 exit(s == 0 ? 1 : 0);
00303 }
00304
00308 static void
00309 init_signals(void)
00310 {
00311 struct sigaction sa;
00312
00313 debug(LOG_DEBUG, "Initializing signal handlers");
00314
00315 sa.sa_handler = sigchld_handler;
00316 sigemptyset(&sa.sa_mask);
00317 sa.sa_flags = SA_RESTART;
00318 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
00319 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00320 exit(1);
00321 }
00322
00323
00324
00325
00326
00327
00328
00329 sa.sa_handler = SIG_IGN;
00330 if (sigaction(SIGPIPE, &sa, NULL) == -1) {
00331 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00332 exit(1);
00333 }
00334
00335 sa.sa_handler = termination_handler;
00336 sigemptyset(&sa.sa_mask);
00337 sa.sa_flags = SA_RESTART;
00338
00339
00340 if (sigaction(SIGTERM, &sa, NULL) == -1) {
00341 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00342 exit(1);
00343 }
00344
00345
00346 if (sigaction(SIGQUIT, &sa, NULL) == -1) {
00347 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00348 exit(1);
00349 }
00350
00351
00352 if (sigaction(SIGINT, &sa, NULL) == -1) {
00353 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00354 exit(1);
00355 }
00356 }
00357
00361 static void
00362 main_loop(void)
00363 {
00364 int result;
00365 pthread_t tid;
00366 s_config *config = config_get_config();
00367 request *r;
00368 void **params;
00369
00370
00371 if (!started_time) {
00372 debug(LOG_INFO, "Setting started_time");
00373 started_time = time(NULL);
00374 }
00375 else if (started_time < MINIMUM_STARTED_TIME) {
00376 debug(LOG_WARNING, "Detected possible clock skew - re-setting started_time");
00377 started_time = time(NULL);
00378 }
00379
00380
00381 if (!config->gw_address) {
00382 debug(LOG_DEBUG, "Finding IP address of %s", config->gw_interface);
00383 if ((config->gw_address = get_iface_ip(config->gw_interface)) == NULL) {
00384 debug(LOG_ERR, "Could not get IP address information of %s, exiting...", config->gw_interface);
00385 exit(1);
00386 }
00387 debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_address);
00388 }
00389
00390
00391
00392 if (!config->gw_id) {
00393 debug(LOG_DEBUG, "Finding MAC address of %s", config->gw_interface);
00394 if ((config->gw_id = get_iface_mac(config->gw_interface)) == NULL) {
00395 debug(LOG_ERR, "Could not get MAC address information of %s, exiting...", config->gw_interface);
00396 exit(1);
00397 }
00398 debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_id);
00399 }
00400
00401
00402 debug(LOG_NOTICE, "Creating web server on %s:%d", config->gw_address, config->gw_port);
00403 if ((webserver = httpdCreate(config->gw_address, config->gw_port)) == NULL) {
00404 debug(LOG_ERR, "Could not create web server: %s", strerror(errno));
00405 exit(1);
00406 }
00407
00408 debug(LOG_DEBUG, "Assigning callbacks to web server");
00409 httpdAddCContent(webserver, "/", "wifidog", 0, NULL, http_callback_wifidog);
00410 httpdAddCContent(webserver, "/wifidog", "", 0, NULL, http_callback_wifidog);
00411 httpdAddCContent(webserver, "/wifidog", "about", 0, NULL, http_callback_about);
00412 httpdAddCContent(webserver, "/wifidog", "status", 0, NULL, http_callback_status);
00413 httpdAddCContent(webserver, "/wifidog", "auth", 0, NULL, http_callback_auth);
00414
00415 httpdAddC404Content(webserver, http_callback_404);
00416
00417
00418 fw_destroy();
00419
00420 if (!fw_init()) {
00421 debug(LOG_ERR, "FATAL: Failed to initialize firewall");
00422 exit(1);
00423 }
00424
00425
00426 result = pthread_create(&tid_fw_counter, NULL, (void *)thread_client_timeout_check, NULL);
00427 if (result != 0) {
00428 debug(LOG_ERR, "FATAL: Failed to create a new thread (fw_counter) - exiting");
00429 termination_handler(0);
00430 }
00431 pthread_detach(tid_fw_counter);
00432
00433
00434 result = pthread_create(&tid, NULL, (void *)thread_wdctl, (void *)safe_strdup(config->wdctl_sock));
00435 if (result != 0) {
00436 debug(LOG_ERR, "FATAL: Failed to create a new thread (wdctl) - exiting");
00437 termination_handler(0);
00438 }
00439 pthread_detach(tid);
00440
00441
00442 result = pthread_create(&tid_ping, NULL, (void *)thread_ping, NULL);
00443 if (result != 0) {
00444 debug(LOG_ERR, "FATAL: Failed to create a new thread (ping) - exiting");
00445 termination_handler(0);
00446 }
00447 pthread_detach(tid_ping);
00448
00449 debug(LOG_NOTICE, "Waiting for connections");
00450 while(1) {
00451 r = httpdGetConnection(webserver, NULL);
00452
00453
00454
00455 if (webserver->lastError == -1) {
00456
00457 continue;
00458 }
00459 else if (webserver->lastError < -1) {
00460
00461
00462
00463
00464
00465 debug(LOG_ERR, "FATAL: httpdGetConnection returned unexpected value %d, exiting.", webserver->lastError);
00466 termination_handler(0);
00467 }
00468 else if (r != NULL) {
00469
00470
00471
00472
00473
00474 debug(LOG_INFO, "Received connection from %s, spawning worker thread", r->clientAddr);
00475
00476
00477 params = safe_malloc(2 * sizeof(void *));
00478 *params = webserver;
00479 *(params + 1) = r;
00480
00481 result = pthread_create(&tid, NULL, (void *)thread_httpd, (void *)params);
00482 if (result != 0) {
00483 debug(LOG_ERR, "FATAL: Failed to create a new thread (httpd) - exiting");
00484 termination_handler(0);
00485 }
00486 pthread_detach(tid);
00487 }
00488 else {
00489
00490
00491
00492 }
00493 }
00494
00495
00496 }
00497
00499 int main(int argc, char **argv) {
00500
00501 s_config *config = config_get_config();
00502 config_init();
00503
00504 parse_commandline(argc, argv);
00505
00506
00507 config_read(config->configfile);
00508 config_validate();
00509
00510
00511 client_list_init();
00512
00513
00514 init_signals();
00515
00516 if (restart_orig_pid) {
00517
00518
00519
00520 get_clients_from_parent();
00521
00522
00523
00524
00525 while (kill(restart_orig_pid, 0) != -1) {
00526 debug(LOG_INFO, "Waiting for parent PID %d to die before continuing loading", restart_orig_pid);
00527 sleep(1);
00528 }
00529
00530 debug(LOG_INFO, "Parent PID %d seems to be dead. Continuing loading.");
00531 }
00532
00533 if (config->daemon) {
00534
00535 debug(LOG_INFO, "Forking into background");
00536
00537 switch(safe_fork()) {
00538 case 0:
00539 setsid();
00540 append_x_restartargv();
00541 main_loop();
00542 break;
00543
00544 default:
00545 exit(0);
00546 break;
00547 }
00548 }
00549 else {
00550 append_x_restartargv();
00551 main_loop();
00552 }
00553
00554 return(0);
00555 }