created tnc-pdp policy decision point plugin

This commit is contained in:
Andreas Steffen 2011-11-13 21:56:47 +01:00
parent bc403eb1e5
commit 70fd2d1af7
9 changed files with 474 additions and 0 deletions

View 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

View 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

View File

@ -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

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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

View File

@ -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"