]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
whitelist: use a stream service to accept client connections
authorMartin Willi <martin@revosec.ch>
Mon, 1 Jul 2013 12:47:11 +0000 (14:47 +0200)
committerMartin Willi <martin@revosec.ch>
Thu, 18 Jul 2013 14:00:29 +0000 (16:00 +0200)
Use SOCK_STREAM, as we don't have SOCK_SEQPACKET on TCP. To have network
transparency, the message now uses network byte order.

src/libcharon/plugins/whitelist/whitelist.c
src/libcharon/plugins/whitelist/whitelist_control.c
src/libcharon/plugins/whitelist/whitelist_msg.h

index 0a3a344593d71207221bb3e5d1b80b70898ca4be..f5fa6f60f1322e1dd8eb5a391c79aca7b991de06 100644 (file)
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <errno.h>
+#include <arpa/inet.h>
 
 /**
  * Connect to the daemon, return FD
  */
 static int make_connection()
 {
-       struct sockaddr_un addr;
-       int fd;
+       union {
+               struct sockaddr_un un;
+               struct sockaddr_in in;
+               struct sockaddr sa;
+       } addr;
+       int fd, len;
 
-       addr.sun_family = AF_UNIX;
-       strcpy(addr.sun_path, WHITELIST_SOCKET);
+       if (getenv("TCP_PORT"))
+       {
+               addr.in.sin_family = AF_INET;
+               addr.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+               addr.in.sin_port = htons(atoi(getenv("TCP_PORT")));
+               len = sizeof(addr.in);
+       }
+       else
+       {
+               addr.un.sun_family = AF_UNIX;
+               strcpy(addr.un.sun_path, WHITELIST_SOCKET);
 
-       fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+               len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.un.sun_path);
+       }
+       fd = socket(addr.sa.sa_family, SOCK_STREAM, 0);
        if (fd < 0)
        {
                fprintf(stderr, "opening socket failed: %s\n", strerror(errno));
                return -1;
        }
-       if (connect(fd, (struct sockaddr *)&addr,
-                       offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path)) < 0)
+       if (connect(fd, &addr.sa, len) < 0)
        {
-               fprintf(stderr, "connecting to %s failed: %s\n",
-                               WHITELIST_SOCKET, strerror(errno));
+               fprintf(stderr, "connecting failed: %s\n", strerror(errno));
                close(fd);
                return -1;
        }
        return fd;
 }
 
+static int read_all(int fd, void *buf, size_t len)
+{
+       ssize_t ret, done = 0;
+
+       while (done < len)
+       {
+               ret = read(fd, buf, len - done);
+               if (ret == -1 && errno == EINTR)
+               {       /* interrupted, try again */
+                       continue;
+               }
+               if (ret < 0)
+               {
+                       return -1;
+               }
+               done += ret;
+               buf += ret;
+       }
+       return len;
+}
+
+static int write_all(int fd, void *buf, size_t len)
+{
+       ssize_t ret, done = 0;
+
+       while (done < len)
+       {
+               ret = write(fd, buf, len - done);
+               if (ret == -1 && errno == EINTR)
+               {       /* interrupted, try again */
+                       continue;
+               }
+               if (ret < 0)
+               {
+                       return -1;
+               }
+               done += ret;
+               buf += ret;
+       }
+       return len;
+}
+
 /**
  * Send a single message
  */
 static int send_msg(int type, char *id)
 {
        whitelist_msg_t msg = {
-               .type = type,
+               .type = htonl(type),
        };
        int fd;
 
@@ -66,7 +123,7 @@ static int send_msg(int type, char *id)
                return 2;
        }
        snprintf(msg.id, sizeof(msg.id), "%s", id);
-       if (send(fd, &msg, sizeof(msg), 0) != sizeof(msg))
+       if (write_all(fd, &msg, sizeof(msg)) != sizeof(msg))
        {
                fprintf(stderr, "writing to socket failed: %s\n", strerror(errno));
                close(fd);
@@ -74,9 +131,15 @@ static int send_msg(int type, char *id)
        }
        if (type == WHITELIST_LIST)
        {
-               while (recv(fd, &msg, sizeof(msg), 0) == sizeof(msg))
+               while (1)
                {
-                       if (msg.type != WHITELIST_LIST)
+                       if (read_all(fd, &msg, sizeof(msg)) != sizeof(msg))
+                       {
+                               fprintf(stderr, "reading failed: %s\n", strerror(errno));
+                               close(fd);
+                               return 2;
+                       }
+                       if (ntohl(msg.type) != WHITELIST_LIST)
                        {
                                break;
                        }
@@ -94,7 +157,7 @@ static int send_msg(int type, char *id)
 static int send_batch(int type, char *file)
 {
        whitelist_msg_t msg = {
-               .type = type,
+               .type = htonl(type),
        };
        FILE *f = stdin;
        int fd, len;
@@ -125,7 +188,7 @@ static int send_batch(int type, char *file)
                {
                        msg.id[len-1] = '\0';
                }
-               if (send(fd, &msg, sizeof(msg), 0) != sizeof(msg))
+               if (write_all(fd, &msg, sizeof(msg)) != sizeof(msg))
                {
                        fprintf(stderr, "writing to socket failed: %s\n", strerror(errno));
                        if (f != stdin)
index b90b62ac1e900eb0087b2a3c1f64b8f9b3bf136c..c3f7ac40eb1aa506c9db289d61e5ff1f643c3b87 100644 (file)
@@ -23,8 +23,6 @@
 #include <errno.h>
 
 #include <daemon.h>
-#include <threading/thread.h>
-#include <processing/jobs/callback_job.h>
 
 #include "whitelist_msg.h"
 
@@ -46,65 +44,28 @@ struct private_whitelist_control_t {
        whitelist_listener_t *listener;
 
        /**
-        * Whitelist unix socket file descriptor
+        * Whitelist stream service
         */
-       int socket;
+       stream_service_t *service;
 };
 
 /**
- * Open whitelist unix socket
+ * Dispatch a received message
  */
-static bool open_socket(private_whitelist_control_t *this)
+static bool on_accept(private_whitelist_control_t *this, stream_t *stream)
 {
-       struct sockaddr_un addr;
-       mode_t old;
-
-       addr.sun_family = AF_UNIX;
-       strcpy(addr.sun_path, WHITELIST_SOCKET);
+       identification_t *id, *current;
+       enumerator_t *enumerator;
+       whitelist_msg_t msg;
 
-       this->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
-       if (this->socket == -1)
+       if (!stream->read_all(stream, &msg, sizeof(msg)))
        {
-               DBG1(DBG_CFG, "creating whitelist socket failed");
                return FALSE;
        }
-       unlink(addr.sun_path);
-       old = umask(~(S_IRWXU | S_IRWXG));
-       if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) < 0)
-       {
-               DBG1(DBG_CFG, "binding whitelist socket failed: %s", strerror(errno));
-               close(this->socket);
-               return FALSE;
-       }
-       umask(old);
-       if (chown(addr.sun_path, lib->caps->get_uid(lib->caps),
-                         lib->caps->get_gid(lib->caps)) != 0)
-       {
-               DBG1(DBG_CFG, "changing whitelist socket permissions failed: %s",
-                        strerror(errno));
-       }
-       if (listen(this->socket, 10) < 0)
-       {
-               DBG1(DBG_CFG, "listening on whitelist socket failed: %s", strerror(errno));
-               close(this->socket);
-               unlink(addr.sun_path);
-               return FALSE;
-       }
-       return TRUE;
-}
 
-/**
- * Dispatch a received message
- */
-static void dispatch(private_whitelist_control_t *this,
-                                        int fd, whitelist_msg_t *msg)
-{
-       identification_t *id, *current;
-       enumerator_t *enumerator;
-
-       msg->id[sizeof(msg->id)-1] = 0;
-       id = identification_create_from_string(msg->id);
-       switch (msg->type)
+       msg.id[sizeof(msg.id) - 1] = 0;
+       id = identification_create_from_string(msg.id);
+       switch (ntohl(msg.type))
        {
                case WHITELIST_ADD:
                        this->listener->add(this->listener, id);
@@ -118,8 +79,8 @@ static void dispatch(private_whitelist_control_t *this,
                        {
                                if (current->matches(current, id))
                                {
-                                       snprintf(msg->id, sizeof(msg->id), "%Y", current);
-                                       if (send(fd, msg, sizeof(*msg), 0) != sizeof(*msg))
+                                       snprintf(msg.id, sizeof(msg.id), "%Y", current);
+                                       if (!stream->write_all(stream, &msg, sizeof(msg)))
                                        {
                                                DBG1(DBG_CFG, "listing whitelist failed");
                                                break;
@@ -127,9 +88,9 @@ static void dispatch(private_whitelist_control_t *this,
                                }
                        }
                        enumerator->destroy(enumerator);
-                       msg->type = WHITELIST_END;
-                       memset(msg->id, 0, sizeof(msg->id));
-                       send(fd, msg, sizeof(*msg), 0);
+                       msg.type = htonl(WHITELIST_END);
+                       memset(msg.id, 0, sizeof(msg.id));
+                       stream->write_all(stream, &msg, sizeof(msg));
                        break;
                case WHITELIST_FLUSH:
                        this->listener->flush(this->listener, id);
@@ -145,58 +106,14 @@ static void dispatch(private_whitelist_control_t *this,
                        break;
        }
        id->destroy(id);
-}
-
-/**
- * Accept whitelist control connections, dispatch
- */
-static job_requeue_t receive(private_whitelist_control_t *this)
-{
-       struct sockaddr_un addr;
-       int fd, len = sizeof(addr);
-       whitelist_msg_t msg;
-       bool oldstate;
-
-       oldstate = thread_cancelability(TRUE);
-       fd = accept(this->socket, (struct sockaddr*)&addr, &len);
-       thread_cancelability(oldstate);
-
-       if (fd != -1)
-       {
-               while (TRUE)
-               {
-                       oldstate = thread_cancelability(TRUE);
-                       len = recv(fd, &msg, sizeof(msg), 0);
-                       thread_cancelability(oldstate);
 
-                       if (len == sizeof(msg))
-                       {
-                               dispatch(this, fd, &msg);
-                       }
-                       else
-                       {
-                               if (len != 0)
-                               {
-                                       DBG1(DBG_CFG, "receiving whitelist msg failed: %s",
-                                                strerror(errno));
-                               }
-                               break;
-                       }
-               }
-               close(fd);
-       }
-       else
-       {
-               DBG1(DBG_CFG, "accepting whitelist connection failed: %s",
-                        strerror(errno));
-       }
-       return JOB_REQUEUE_FAIR;
+       return FALSE;
 }
 
 METHOD(whitelist_control_t, destroy, void,
        private_whitelist_control_t *this)
 {
-       close(this->socket);
+       this->service->destroy(this->service);
        free(this);
 }
 
@@ -206,6 +123,7 @@ METHOD(whitelist_control_t, destroy, void,
 whitelist_control_t *whitelist_control_create(whitelist_listener_t *listener)
 {
        private_whitelist_control_t *this;
+       char *uri;
 
        INIT(this,
                .public = {
@@ -214,15 +132,19 @@ whitelist_control_t *whitelist_control_create(whitelist_listener_t *listener)
                .listener = listener,
        );
 
-       if (!open_socket(this))
+       uri = lib->settings->get_str(lib->settings,
+                               "%s.plugins.whitelist.socket", "unix://" WHITELIST_SOCKET,
+                               charon->name);
+       this->service = lib->streams->create_service(lib->streams, uri, 10);
+       if (!this->service)
        {
+               DBG1(DBG_CFG, "creating whitelist socket failed");
                free(this);
                return NULL;
        }
 
-       lib->processor->queue_job(lib->processor,
-               (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive, this,
-                               NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
+       this->service->on_accept(this->service, (stream_service_cb_t)on_accept,
+                                                        this, JOB_PRIO_CRITICAL, 0);
 
        return &this->public;
 }
index 65b922996b6f60c775b490bcc4733cd64b397968..595fb6ffb69cab5658bba473e75b9b952ee16cdd 100644 (file)
@@ -53,6 +53,6 @@ struct whitelist_msg_t {
        int type;
        /** null terminated identity */
        char id[128];
-};
+} __attribute__((packed));
 
 #endif /** WHITELIST_MSG_H_ @}*/