]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Added infrastructure to listen to RADIUS Dynamic Authorization Extension requests
authorMartin Willi <martin@revosec.ch>
Wed, 22 Feb 2012 09:34:06 +0000 (10:34 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 5 Mar 2012 17:06:13 +0000 (18:06 +0100)
src/libcharon/plugins/eap_radius/Makefile.am
src/libcharon/plugins/eap_radius/eap_radius_dae.c [new file with mode: 0644]
src/libcharon/plugins/eap_radius/eap_radius_dae.h [new file with mode: 0644]

index c07f9ab95148076bcc0c2a5b649c7cad03ebf4e8..403f858068bac68ab6bd02c311508610b0ec88fe 100644 (file)
@@ -14,6 +14,7 @@ libstrongswan_eap_radius_la_SOURCES = \
        eap_radius_plugin.h eap_radius_plugin.c \
        eap_radius.h eap_radius.c \
        eap_radius_accounting.h eap_radius_accounting.c \
+       eap_radius_dae.h eap_radius_dae.c \
        radius_server.h radius_server.c \
        radius_socket.h radius_socket.c \
        radius_client.h radius_client.c \
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.c b/src/libcharon/plugins/eap_radius/eap_radius_dae.c
new file mode 100644 (file)
index 0000000..c6f5d84
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "eap_radius_dae.h"
+
+#include "radius_message.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <daemon.h>
+#include <threading/thread.h>
+#include <processing/jobs/callback_job.h>
+
+#define RADIUS_DAE_PORT 3799
+
+typedef struct private_eap_radius_dae_t private_eap_radius_dae_t;
+
+/**
+ * Private data of an eap_radius_dae_t object.
+ */
+struct private_eap_radius_dae_t {
+
+       /**
+        * Public eap_radius_dae_t interface.
+        */
+       eap_radius_dae_t public;
+
+       /**
+        * RADIUS session state
+        */
+       eap_radius_accounting_t *accounting;
+
+       /**
+        * Socket to listen on authorization extension port
+        */
+       int fd;
+
+       /**
+        * Listen job
+        */
+       callback_job_t *job;
+};
+
+/**
+ * Receive RADIUS DAE requests
+ */
+static job_requeue_t receive(private_eap_radius_dae_t *this)
+{
+       struct sockaddr_storage addr;
+       socklen_t addr_len = sizeof(addr);
+       radius_message_t *request;
+       char buf[2048];
+       ssize_t len;
+       bool oldstate;
+
+       oldstate = thread_cancelability(TRUE);
+       len = recvfrom(this->fd, buf, sizeof(buf), 0,
+                                  (struct sockaddr*)&addr, &addr_len);
+       thread_cancelability(oldstate);
+
+       if (len > 0)
+       {
+               request = radius_message_parse_response(chunk_create(buf, len));
+               if (request)
+               {
+                       switch (request->get_code(request))
+                       {
+                               case RMC_DISCONNECT_REQUEST:
+                                       /* TODO */
+                               case RMC_COA_REQUEST:
+                                       /* TODO */
+                               default:
+                                       DBG1(DBG_CFG, "ignoring unsupported RADIUS DAE %N message",
+                                                radius_message_code_names, request->get_code(request));
+                               break;
+                       }
+                       request->destroy(request);
+               }
+               else
+               {
+                       DBG1(DBG_NET, "ignoring invalid RADIUS DAE request");
+               }
+       }
+       else
+       {
+               DBG1(DBG_NET, "receving RADIUS DAE request failed: %s", strerror(errno));
+       }
+       return JOB_REQUEUE_DIRECT;
+}
+
+/**
+ * Open DAE socket
+ */
+static bool open_socket(private_eap_radius_dae_t *this)
+{
+       host_t *host;
+
+       this->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       if (this->fd == -1)
+       {
+               DBG1(DBG_CFG, "unable to open RADIUS DAE socket: %s", strerror(errno));
+               return FALSE;
+       }
+
+       host = host_create_from_string(
+                               lib->settings->get_str(lib->settings,
+                                       "charon.plugins.eap-radius.dae.listen", "0.0.0.0"),
+                               lib->settings->get_int(lib->settings,
+                                       "charon.plugins.eap-radius.dae.port", RADIUS_DAE_PORT));
+       if (!host)
+       {
+               DBG1(DBG_CFG, "invalid RADIUS DAE listen address");
+               return FALSE;
+       }
+
+       if (bind(this->fd, host->get_sockaddr(host),
+                        *host->get_sockaddr_len(host)) == -1)
+       {
+               DBG1(DBG_CFG, "unable to bind RADIUS DAE socket: %s", strerror(errno));
+               host->destroy(host);
+               return FALSE;
+       }
+       host->destroy(host);
+       return TRUE;
+}
+
+METHOD(eap_radius_dae_t, destroy, void,
+       private_eap_radius_dae_t *this)
+{
+       if (this->job)
+       {
+               this->job->cancel(this->job);
+       }
+       if (this->fd != -1)
+       {
+               close(this->fd);
+       }
+       free(this);
+}
+
+/**
+ * See header
+ */
+eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting)
+{
+       private_eap_radius_dae_t *this;
+
+       INIT(this,
+               .public = {
+                       .destroy = _destroy,
+               },
+               .accounting = accounting,
+               .fd = -1,
+       );
+
+       if (!open_socket(this))
+       {
+               destroy(this);
+               return NULL;
+       }
+
+       this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
+                                                                               this, NULL, NULL, JOB_PRIO_CRITICAL);
+       lib->processor->queue_job(lib->processor, (job_t*)this->job);
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.h b/src/libcharon/plugins/eap_radius/eap_radius_dae.h
new file mode 100644 (file)
index 0000000..759eadb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup eap_radius_dae eap_radius_dae
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef EAP_RADIUS_DAE_H_
+#define EAP_RADIUS_DAE_H_
+
+#include "eap_radius_accounting.h"
+
+typedef struct eap_radius_dae_t eap_radius_dae_t;
+
+/**
+ * Dynamic Authorization Extensions (RFC 5176) for EAP-RADIUS.
+ */
+struct eap_radius_dae_t {
+
+       /**
+        * Destroy a eap_radius_dae_t.
+        */
+       void (*destroy)(eap_radius_dae_t *this);
+};
+
+/**
+ * Create a eap_radius_dae instance.
+ */
+eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting);
+
+#endif /** EAP_RADIUS_DAE_H_ @}*/