00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #define _GNU_SOURCE
00028
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <pthread.h>
00032 #include <string.h>
00033 #include <stdarg.h>
00034 #include <sys/types.h>
00035 #include <sys/socket.h>
00036 #include <sys/un.h>
00037 #include <unistd.h>
00038 #include <syslog.h>
00039 #include <signal.h>
00040 #include <errno.h>
00041
00042 #include "common.h"
00043 #include "httpd.h"
00044 #include "util.h"
00045 #include "conf.h"
00046 #include "debug.h"
00047 #include "auth.h"
00048 #include "centralserver.h"
00049 #include "fw_iptables.h"
00050 #include "firewall.h"
00051 #include "client_list.h"
00052 #include "wdctl_thread.h"
00053
00054
00055 extern pthread_mutex_t client_list_mutex;
00056 extern pthread_mutex_t config_mutex;
00057
00058
00059 extern char ** restartargv;
00060 static void *thread_wdctl_handler(void *);
00061 static void wdctl_status(int);
00062 static void wdctl_stop(int);
00063 static void wdctl_reset(int, char *);
00064 static void wdctl_restart(int);
00065
00070 void
00071 thread_wdctl(void *arg)
00072 {
00073 int fd;
00074 char *sock_name;
00075 struct sockaddr_un sa_un;
00076 int result;
00077 pthread_t tid;
00078 socklen_t len;
00079
00080 debug(LOG_DEBUG, "Starting wdctl.");
00081
00082 memset(&sa_un, 0, sizeof(sa_un));
00083 sock_name = (char *)arg;
00084 debug(LOG_DEBUG, "Socket name: %s", sock_name);
00085
00086 if (strlen(sock_name) > (sizeof(sa_un.sun_path) - 1)) {
00087
00088 debug(LOG_ERR, "WDCTL socket name too long");
00089 exit(1);
00090 }
00091
00092
00093 debug(LOG_DEBUG, "Creating socket");
00094 wdctl_socket_server = socket(PF_UNIX, SOCK_STREAM, 0);
00095
00096 debug(LOG_DEBUG, "Got server socket %d", wdctl_socket_server);
00097
00098
00099 unlink(sock_name);
00100
00101 debug(LOG_DEBUG, "Filling sockaddr_un");
00102 strcpy(sa_un.sun_path, sock_name);
00103
00104 sa_un.sun_family = AF_UNIX;
00105
00106 debug(LOG_DEBUG, "Binding socket (%s) (%d)", sa_un.sun_path,
00107 strlen(sock_name));
00108
00109
00110 if (bind(wdctl_socket_server, (struct sockaddr *)&sa_un, strlen(sock_name)
00111 + sizeof(sa_un.sun_family))) {
00112 debug(LOG_ERR, "Could not bind control socket: %s",
00113 strerror(errno));
00114 pthread_exit(NULL);
00115 }
00116
00117 if (listen(wdctl_socket_server, 5)) {
00118 debug(LOG_ERR, "Could not listen on control socket: %s",
00119 strerror(errno));
00120 pthread_exit(NULL);
00121 }
00122
00123 while (1) {
00124 len = sizeof(sa_un);
00125 memset(&sa_un, 0, len);
00126 if ((fd = accept(wdctl_socket_server, (struct sockaddr *)&sa_un, &len)) == -1){
00127 debug(LOG_ERR, "Accept failed on control socket: %s",
00128 strerror(errno));
00129 } else {
00130 debug(LOG_DEBUG, "Accepted connection on wdctl socket %d (%s)", fd, sa_un.sun_path);
00131 result = pthread_create(&tid, NULL, &thread_wdctl_handler, (void *)fd);
00132 if (result != 0) {
00133 debug(LOG_ERR, "FATAL: Failed to create a new thread (wdctl handler) - exiting");
00134 termination_handler(0);
00135 }
00136 pthread_detach(tid);
00137 }
00138 }
00139 }
00140
00141
00142 static void *
00143 thread_wdctl_handler(void *arg)
00144 {
00145 int fd,
00146 done,
00147 i;
00148 char request[MAX_BUF];
00149 ssize_t read_bytes,
00150 len;
00151
00152 debug(LOG_DEBUG, "Entering thread_wdctl_handler....");
00153
00154 fd = (int)arg;
00155
00156 debug(LOG_DEBUG, "Read bytes and stuff from %d", fd);
00157
00158
00159 read_bytes = 0;
00160 done = 0;
00161 memset(request, 0, sizeof(request));
00162
00163
00164 while (!done && read_bytes < (sizeof(request) - 1)) {
00165 len = read(fd, request + read_bytes,
00166 sizeof(request) - read_bytes);
00167
00168
00169 for (i = read_bytes; i < (read_bytes + len); i++) {
00170 if (request[i] == '\r' || request[i] == '\n') {
00171 request[i] = '\0';
00172 done = 1;
00173 }
00174 }
00175
00176
00177 read_bytes += len;
00178 }
00179
00180 if (strncmp(request, "status", 6) == 0) {
00181 wdctl_status(fd);
00182 } else if (strncmp(request, "stop", 4) == 0) {
00183 wdctl_stop(fd);
00184 } else if (strncmp(request, "reset", 5) == 0) {
00185 wdctl_reset(fd, (request + 6));
00186 } else if (strncmp(request, "restart", 7) == 0) {
00187 wdctl_restart(fd);
00188 }
00189
00190 if (!done) {
00191 debug(LOG_ERR, "Invalid wdctl request.");
00192 shutdown(fd, 2);
00193 close(fd);
00194 pthread_exit(NULL);
00195 }
00196
00197 debug(LOG_DEBUG, "Request received: [%s]", request);
00198
00199 shutdown(fd, 2);
00200 close(fd);
00201 debug(LOG_DEBUG, "Exiting thread_wdctl_handler....");
00202
00203 return NULL;
00204 }
00205
00206 static void
00207 wdctl_status(int fd)
00208 {
00209 char * status = NULL;
00210 int len = 0;
00211
00212 status = get_status_text();
00213 len = strlen(status);
00214
00215 write(fd, status, len);
00216
00217 free(status);
00218 }
00219
00221 static void
00222 wdctl_stop(int fd)
00223 {
00224 pid_t pid;
00225
00226 pid = getpid();
00227 kill(pid, SIGINT);
00228 }
00229
00230 static void
00231 wdctl_restart(int afd)
00232 {
00233 int sock,
00234 fd;
00235 char *sock_name;
00236 struct sockaddr_un sa_un;
00237 int result;
00238 s_config * conf = NULL;
00239 t_client * client = NULL;
00240 char * tempstring = NULL;
00241 pid_t pid;
00242 ssize_t written;
00243 socklen_t len;
00244
00245 conf = config_get_config();
00246
00247 debug(LOG_NOTICE, "Will restart myself");
00248
00249
00250
00251
00252 memset(&sa_un, 0, sizeof(sa_un));
00253 sock_name = conf->internal_sock;
00254 debug(LOG_DEBUG, "Socket name: %s", sock_name);
00255
00256 if (strlen(sock_name) > (sizeof(sa_un.sun_path) - 1)) {
00257
00258 debug(LOG_ERR, "INTERNAL socket name too long");
00259 return;
00260 }
00261
00262 debug(LOG_DEBUG, "Creating socket");
00263 sock = socket(PF_UNIX, SOCK_STREAM, 0);
00264
00265 debug(LOG_DEBUG, "Got internal socket %d", sock);
00266
00267
00268 unlink(sock_name);
00269
00270 debug(LOG_DEBUG, "Filling sockaddr_un");
00271 strcpy(sa_un.sun_path, sock_name);
00272 sa_un.sun_family = AF_UNIX;
00273
00274 debug(LOG_DEBUG, "Binding socket (%s) (%d)", sa_un.sun_path, strlen(sock_name));
00275
00276
00277 if (bind(sock, (struct sockaddr *)&sa_un, strlen(sock_name) + sizeof(sa_un.sun_family))) {
00278 debug(LOG_ERR, "Could not bind internal socket: %s", strerror(errno));
00279 return;
00280 }
00281
00282 if (listen(sock, 5)) {
00283 debug(LOG_ERR, "Could not listen on internal socket: %s", strerror(errno));
00284 return;
00285 }
00286
00287
00288
00289
00290 debug(LOG_DEBUG, "Forking in preparation for exec()...");
00291 pid = safe_fork();
00292 if (pid > 0) {
00293
00294
00295
00296 debug(LOG_DEBUG, "Waiting for child to connect on internal socket");
00297 len = sizeof(sa_un);
00298 if ((fd = accept(sock, (struct sockaddr *)&sa_un, &len)) == -1){
00299 debug(LOG_ERR, "Accept failed on internal socket: %s", strerror(errno));
00300 close(sock);
00301 return;
00302 }
00303
00304 close(sock);
00305
00306 debug(LOG_DEBUG, "Received connection from child. Sending them all existing clients");
00307
00308
00309 LOCK_CLIENT_LIST();
00310 client = client_get_first_client();
00311 while (client) {
00312
00313 safe_asprintf(&tempstring, "CLIENT|ip=%s|mac=%s|token=%s|fw_connection_state=%u|fd=%d|counters_incoming=%llu|counters_outgoing=%llu|counters_last_updated=%lu\n", client->ip, client->mac, client->token, client->fw_connection_state, client->fd, client->counters.incoming, client->counters.outgoing, client->counters.last_updated);
00314 debug(LOG_DEBUG, "Sending to child client data: %s", tempstring);
00315 len = 0;
00316 while (len != strlen(tempstring)) {
00317 written = write(fd, (tempstring + len), strlen(tempstring) - len);
00318 if (written == -1) {
00319 debug(LOG_ERR, "Failed to write client data to child: %s", strerror(errno));
00320 free(tempstring);
00321 break;
00322 }
00323 else {
00324 len += written;
00325 }
00326 }
00327 free(tempstring);
00328 client = client->next;
00329 }
00330 UNLOCK_CLIENT_LIST();
00331
00332 close(fd);
00333
00334 debug(LOG_INFO, "Sent all existing clients to child. Committing suicide!");
00335
00336 shutdown(afd, 2);
00337 close(afd);
00338
00339
00340 wdctl_stop(afd);
00341 }
00342 else {
00343
00344 close(wdctl_socket_server);
00345 close(icmp_fd);
00346 close(sock);
00347 shutdown(afd, 2);
00348 close(afd);
00349 debug(LOG_NOTICE, "Re-executing myself (%s)", restartargv[0]);
00350 setsid();
00351 execvp(restartargv[0], restartargv);
00352
00353 debug(LOG_ERR, "I failed to re-execute myself: %s", strerror(errno));
00354 debug(LOG_ERR, "Exiting without cleanup");
00355 exit(1);
00356 }
00357
00358 }
00359
00360 static void
00361 wdctl_reset(int fd, char *arg)
00362 {
00363 t_client *node;
00364
00365 debug(LOG_DEBUG, "Entering wdctl_reset...");
00366
00367 LOCK_CLIENT_LIST();
00368 debug(LOG_DEBUG, "Argument: %s (@%x)", arg, arg);
00369
00370
00371 if ((node = client_list_find_by_ip(arg)) != NULL);
00372 else if ((node = client_list_find_by_mac(arg)) != NULL);
00373 else {
00374 debug(LOG_DEBUG, "Client not found.");
00375 UNLOCK_CLIENT_LIST();
00376 write(fd, "No", 2);
00377 return;
00378 }
00379
00380 debug(LOG_DEBUG, "Got node %x.", node);
00381
00382
00383
00384
00385 fw_deny(node->ip, node->mac, node->fw_connection_state);
00386 client_list_delete(node);
00387
00388 UNLOCK_CLIENT_LIST();
00389
00390 write(fd, "Yes", 3);
00391
00392 debug(LOG_DEBUG, "Exiting wdctl_reset...");
00393 }