created tnc-pdp policy decision point plugin
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 13 Nov 2011 20:56:47 +0000 (21:56 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 13 Mar 2012 15:27:16 +0000 (16:27 +0100)
configure.in
src/libcharon/Makefile.am
src/libcharon/plugins/tnc_pdp/Makefile.am [new file with mode: 0644]
src/libcharon/plugins/tnc_pdp/tnc_pdp.c [new file with mode: 0644]
src/libcharon/plugins/tnc_pdp/tnc_pdp.h [new file with mode: 0644]
src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c [new file with mode: 0644]
src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h [new file with mode: 0644]
testing/scripts/build-umlrootfs
testing/testing.conf

index 394f666..f533a8b 100644 (file)
@@ -131,6 +131,7 @@ ARG_ENABL_SET([eap-peap],       [enable EAP PEAP authentication module.])
 ARG_ENABL_SET([eap-tnc],        [enable EAP TNC trusted network connect module.])
 ARG_ENABL_SET([eap-radius],     [enable RADIUS proxy authentication module.])
 ARG_ENABL_SET([tnc-ifmap],      [enable TNC IF-MAP module.])
+ARG_ENABL_SET([tnc-pdp],        [enable TNC policy decision point module.])
 ARG_ENABL_SET([tnc-imc],        [enable TNC IMC module.])
 ARG_ENABL_SET([tnc-imv],        [enable TNC IMV module.])
 ARG_ENABL_SET([tnccs-11],       [enable TNCCS 1.1 protocol module.])
@@ -871,6 +872,7 @@ ADD_PLUGIN([eap-ttls],             [c libcharon])
 ADD_PLUGIN([eap-peap],             [c libcharon])
 ADD_PLUGIN([eap-tnc],              [c libcharon])
 ADD_PLUGIN([tnc-ifmap],            [c libcharon])
+ADD_PLUGIN([tnc-pdp],              [c libcharon])
 ADD_PLUGIN([tnc-imc],              [c libcharon])
 ADD_PLUGIN([tnc-imv],              [c libcharon])
 ADD_PLUGIN([tnc-tnccs],            [c libcharon])
@@ -994,6 +996,7 @@ AM_CONDITIONAL(USE_EAP_PEAP, test x$eap_peap = xtrue)
 AM_CONDITIONAL(USE_EAP_TNC, test x$eap_tnc = xtrue)
 AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue)
 AM_CONDITIONAL(USE_TNC_IFMAP, test x$tnc_ifmap = xtrue)
+AM_CONDITIONAL(USE_TNC_PDP, test x$tnc_pdp = xtrue)
 AM_CONDITIONAL(USE_TNC_IMC, test x$tnc_imc = xtrue)
 AM_CONDITIONAL(USE_TNC_IMV, test x$tnc_imv = xtrue)
 AM_CONDITIONAL(USE_TNC_TNCCS, test x$tnc_tnccs = xtrue)
@@ -1172,6 +1175,7 @@ AC_OUTPUT(
        src/libcharon/plugins/eap_tnc/Makefile
        src/libcharon/plugins/eap_radius/Makefile
        src/libcharon/plugins/tnc_ifmap/Makefile
+       src/libcharon/plugins/tnc_pdp/Makefile
        src/libcharon/plugins/tnc_imc/Makefile
        src/libcharon/plugins/tnc_imv/Makefile
        src/libcharon/plugins/tnc_tnccs/Makefile
index edb7665..b86bd42 100644 (file)
@@ -340,6 +340,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_TNC_PDP
+  SUBDIRS += plugins/tnc_pdp
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/tnc_pdp/libstrongswan-tnc-pdp.la
+endif
+endif
+
 if USE_TNC_IMC
   SUBDIRS += plugins/tnc_imc
 if MONOLITHIC
diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.am b/src/libcharon/plugins/tnc_pdp/Makefile.am
new file mode 100644 (file)
index 0000000..7123dd9
--- /dev/null
@@ -0,0 +1,21 @@
+
+INCLUDES = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-tnc-pdp.la
+else
+plugin_LTLIBRARIES = libstrongswan-tnc-pdp.la
+libstrongswan_tnc_pdp_la_LIBADD = \
+       $(top_builddir)/src/libtls/libtls.la \
+       $(top_builddir)/src/libtnccs/libtnccs.la
+endif
+
+libstrongswan_tnc_pdp_la_SOURCES = \
+       tnc_pdp_plugin.h tnc_pdp_plugin.c tnc_pdp.h tnc_pdp.c
+
+libstrongswan_tnc_pdp_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c
new file mode 100644 (file)
index 0000000..f0cf866
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 "tnc_pdp.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <daemon.h>
+#include <debug.h>
+#include <threading/thread.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_tnc_pdp_t private_tnc_pdp_t;
+
+/**
+ * Maximum size of a RADIUS IP packet
+ */
+#define MAX_PACKET 2048
+
+/**
+ * private data of tnc_pdp_t
+ */
+struct private_tnc_pdp_t {
+
+       /**
+        * implements tnc_pdp_t interface
+        */
+       tnc_pdp_t public;
+
+       /**
+        * IPv4 RADIUS socket
+        */
+       int ipv4;
+
+       /**
+        * IPv6 RADIUS socket
+        */
+       int ipv6;
+
+       /**
+        * Callback job dispatching commands
+        */
+       callback_job_t *job;
+
+};
+
+
+/**
+ * Open IPv4 or IPv6 UDP RADIUS socket
+ */
+static int open_socket(private_tnc_pdp_t *this, int family, u_int16_t port)
+{
+       int on = TRUE;
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       int skt;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.ss_family = family;
+
+       /* precalculate constants depending on address family */
+       switch (family)
+       {
+               case AF_INET:
+               {
+                       struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+
+                       htoun32(&sin->sin_addr.s_addr, INADDR_ANY);
+                       htoun16(&sin->sin_port, port);
+                       addrlen = sizeof(struct sockaddr_in);
+                       break;
+               }
+               case AF_INET6:
+               {
+                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+
+                       memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
+                       htoun16(&sin6->sin6_port, port);
+                       addrlen = sizeof(struct sockaddr_in6);
+                       break;
+               }
+               default:
+                       return 0;
+       }
+
+       /* open the socket */
+       skt = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+       if (skt < 0)
+       {
+               DBG1(DBG_NET, "opening RADIUS socket failed: %s", strerror(errno));
+               return 0;
+       }
+       if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+       {
+               DBG1(DBG_NET, "unable to set SO_REUSEADDR on socket: %s", strerror(errno));
+               close(skt);
+               return 0;
+       }
+
+       /* bind the socket */
+       if (bind(skt, (struct sockaddr *)&addr, addrlen) < 0)
+       {
+               DBG1(DBG_NET, "unable to bind RADIUS socket: %s", strerror(errno));
+               close(skt);
+               return 0;
+       }
+
+       return skt;
+}
+
+/**
+ * Process packets received on the RADIUS socket
+ */
+static job_requeue_t receive(private_tnc_pdp_t *this)
+{
+       while (TRUE)
+       {
+               char buffer[MAX_PACKET];
+               int max_fd = 0, selected = 0, bytes_read = 0;
+               fd_set rfds;
+               bool oldstate;
+               host_t *source;
+               struct msghdr msg;
+               struct iovec iov;
+               union {
+                       struct sockaddr_in in4;
+                       struct sockaddr_in6 in6;
+               } src;
+
+               FD_ZERO(&rfds);
+
+               if (this->ipv4)
+               {
+                       FD_SET(this->ipv4, &rfds);
+               }
+               if (this->ipv6)
+               {
+                       FD_SET(this->ipv6, &rfds);
+               }
+               max_fd = max(this->ipv4, this->ipv6);
+
+               DBG2(DBG_NET, "waiting for data on RADIUS sockets");
+               oldstate = thread_cancelability(TRUE);
+               if (select(max_fd + 1, &rfds, NULL, NULL, NULL) <= 0)
+               {
+                       thread_cancelability(oldstate);
+                       continue;
+               }
+               thread_cancelability(oldstate);
+
+               if (FD_ISSET(this->ipv4, &rfds))
+               {
+                       selected = this->ipv4;
+               }
+               else if (FD_ISSET(this->ipv6, &rfds))
+               {
+                       selected = this->ipv6;
+               }
+               else
+               {
+                       /* oops, shouldn't happen */
+                       continue;
+               }
+
+               /* read received packet */
+               msg.msg_name = &src;
+               msg.msg_namelen = sizeof(src);
+               iov.iov_base = buffer;
+               iov.iov_len = MAX_PACKET;
+               msg.msg_iov = &iov;
+               msg.msg_iovlen = 1;
+               msg.msg_flags = 0;
+
+               bytes_read = recvmsg(selected, &msg, 0);
+               if (bytes_read < 0)
+               {
+                       DBG1(DBG_NET, "error reading RADIUS socket: %s", strerror(errno));
+                       continue;
+               }
+               if (msg.msg_flags & MSG_TRUNC)
+               {
+                       DBG1(DBG_NET, "receive buffer too small, RADIUS packet discarded");
+                       continue;
+               }
+               source = host_create_from_sockaddr((sockaddr_t*)&src);
+               DBG2(DBG_NET, "received RADIUS packet from %#H", source);
+               DBG3(DBG_NET, "%b", buffer, bytes_read);
+               source->destroy(source);
+       }
+       return JOB_REQUEUE_FAIR;
+}
+
+METHOD(tnc_pdp_t, destroy, void,
+       private_tnc_pdp_t *this)
+{
+       this->job->cancel(this->job);
+       if (this->ipv4)
+       {
+               close(this->ipv4);
+       }
+       if (this->ipv6)
+       {
+               close(this->ipv6);
+       }
+       free(this);
+}
+
+/*
+ * see header file
+ */
+tnc_pdp_t *tnc_pdp_create(u_int16_t port)
+{
+       private_tnc_pdp_t *this;
+
+       INIT(this,
+               .public = {
+                       .destroy = _destroy,
+               },
+               .ipv4 = open_socket(this, AF_INET,  port),
+               .ipv6 = open_socket(this, AF_INET6, port),
+       );
+
+       if (!this->ipv4 && !this->ipv6)
+       {
+               DBG1(DBG_NET, "couldd not create any RADIUS sockets");
+               destroy(this);
+               return NULL;
+       }
+       if (!this->ipv4)
+       {
+               DBG1(DBG_NET, "could not open IPv4 RADIUS socket, IPv4 disabled");
+       }
+       if (!this->ipv6)
+       {
+               DBG1(DBG_NET, "could not open IPv6 RADIUS socket, IPv6 disabled");
+       }
+
+       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/tnc_pdp/tnc_pdp.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp.h
new file mode 100644 (file)
index 0000000..e769353
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 tnc_pdp tnc_pdp
+ * @{ @ingroup tnc_pdp
+ */
+
+#ifndef TNC_PDP_H_
+#define TNC_PDP_H_
+
+typedef struct tnc_pdp_t tnc_pdp_t;
+
+#include <library.h>
+
+/**
+ * Public interface of a TNC Policy Decision Point object
+ */
+struct tnc_pdp_t {
+
+       /**
+        * implements plugin interface
+        */
+       void (*destroy)(tnc_pdp_t *this);
+};
+
+/**
+ * Create a TNC PDP instance
+ *
+ * @param port         RADIUS port of TNC PDP
+ */
+tnc_pdp_t* tnc_pdp_create(u_int16_t port);
+
+#endif /** TNC_PDP_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c
new file mode 100644 (file)
index 0000000..be9cd75
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 "tnc_pdp_plugin.h"
+#include "tnc_pdp.h"
+
+typedef struct private_tnc_pdp_plugin_t private_tnc_pdp_plugin_t;
+
+/**
+ * Default RADIUS port, when not configured
+ */
+#define RADIUS_PORT 1812
+
+/**
+ * private data of tnc_pdp plugin
+ */
+struct private_tnc_pdp_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       tnc_pdp_plugin_t public;
+
+       /**
+        * Policy Decision Point object
+        */
+       tnc_pdp_t *pdp;
+
+};
+
+METHOD(plugin_t, get_name, char*,
+       private_tnc_pdp_plugin_t *this)
+{
+       return "tnc-pdp";
+}
+
+METHOD(plugin_t, get_features, int,
+       private_tnc_pdp_plugin_t *this, plugin_feature_t *features[])
+{
+       static plugin_feature_t f[] = {
+                       PLUGIN_PROVIDE(CUSTOM, "tnc-pdp"),
+                               PLUGIN_DEPENDS(CUSTOM, "imv-manager"),
+       };
+       *features = f;
+       return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+       private_tnc_pdp_plugin_t *this)
+{
+       DESTROY_IF(this->pdp);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *tnc_pdp_plugin_create()
+{
+       private_tnc_pdp_plugin_t *this;
+       int port;
+
+       port = lib->settings->get_int(lib->settings,
+                                               "charon.plugins.tnc_pdp.radius_port", RADIUS_PORT);
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .get_name = _get_name,
+                               .get_features = _get_features,
+                               .destroy = _destroy,
+                       },
+               },
+               .pdp = tnc_pdp_create(port),
+       );
+
+       return &this->public.plugin;
+}
+
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h
new file mode 100644 (file)
index 0000000..9b8b9ff
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 tnc_pdp tnc_pdp
+ * @ingroup cplugins
+ *
+ * @defgroup tnc_pdp_plugin tnc_pdp_plugin
+ * @{ @ingroup tnc_pdp
+ */
+
+#ifndef TNC_PDP_PLUGIN_H_
+#define TNC_PDP_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct tnc_pdp_plugin_t tnc_pdp_plugin_t;
+
+/**
+ * TNC-PDP plugin
+ */
+struct tnc_pdp_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+#endif /** TNC_PDP_PLUGIN_H_ @}*/
index 2c6e2f0..37d1de6 100755 (executable)
@@ -192,6 +192,11 @@ then
     echo -n " --enable-eap-tnc" >> $INSTALLSHELL
 fi
 
+if [ "$USE_TNC_PDP" = "yes" ]
+then
+    echo -n " --enable-tnc-pdp" >> $INSTALLSHELL
+fi
+
 if [ "$USE_TNC_IMC" = "yes" ]
 then
     echo -n " --enable-tnc-imc" >> $INSTALLSHELL
index ac79ab3..88aa8e1 100755 (executable)
@@ -46,6 +46,7 @@ USE_EAP_TLS="yes"
 USE_EAP_TTLS="yes"
 USE_EAP_PEAP="yes"
 USE_EAP_TNC="yes"
+USE_TNC_PDP="yes"
 USE_TNC_IMC="yes"
 USE_TNC_IMV="yes"
 USE_TNCCS_11="yes"