aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2013-07-01 14:47:11 +0200
committerMartin Willi <martin@revosec.ch>2013-07-18 16:00:29 +0200
commite11c02c8f1591fef64200137c24598fba9d488a9 (patch)
tree37888a2245fa4446222bf1862956dcbb2f72bab2 /src
parent091d0afa2163a6aba79bf4802330f0099e857e38 (diff)
downloadstrongswan-e11c02c8f1591fef64200137c24598fba9d488a9.tar.bz2
strongswan-e11c02c8f1591fef64200137c24598fba9d488a9.tar.xz
whitelist: use a stream service to accept client connections
Use SOCK_STREAM, as we don't have SOCK_SEQPACKET on TCP. To have network transparency, the message now uses network byte order.
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/plugins/whitelist/whitelist.c93
-rw-r--r--src/libcharon/plugins/whitelist/whitelist_control.c132
-rw-r--r--src/libcharon/plugins/whitelist/whitelist_msg.h2
3 files changed, 106 insertions, 121 deletions
diff --git a/src/libcharon/plugins/whitelist/whitelist.c b/src/libcharon/plugins/whitelist/whitelist.c
index 0a3a34459..f5fa6f60f 100644
--- a/src/libcharon/plugins/whitelist/whitelist.c
+++ b/src/libcharon/plugins/whitelist/whitelist.c
@@ -18,45 +18,102 @@
#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)
diff --git a/src/libcharon/plugins/whitelist/whitelist_control.c b/src/libcharon/plugins/whitelist/whitelist_control.c
index b90b62ac1..c3f7ac40e 100644
--- a/src/libcharon/plugins/whitelist/whitelist_control.c
+++ b/src/libcharon/plugins/whitelist/whitelist_control.c
@@ -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;
}
diff --git a/src/libcharon/plugins/whitelist/whitelist_msg.h b/src/libcharon/plugins/whitelist/whitelist_msg.h
index 65b922996..595fb6ffb 100644
--- a/src/libcharon/plugins/whitelist/whitelist_msg.h
+++ b/src/libcharon/plugins/whitelist/whitelist_msg.h
@@ -53,6 +53,6 @@ struct whitelist_msg_t {
int type;
/** null terminated identity */
char id[128];
-};
+} __attribute__((packed));
#endif /** WHITELIST_MSG_H_ @}*/