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