aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2016-03-10 12:00:56 +0100
committerTobias Brunner <tobias@strongswan.org>2016-03-10 12:06:46 +0100
commit709998e10634b98a0888a93b8b0586daa872e748 (patch)
treeb372ccc764216ea244c6f2a8460e0939a8db2a44 /src
parentf893b47e3d854f4051b8d1549cdc0d6d661aa235 (diff)
parent7e854f4d5139204f27946f9c79b1b7486acefcd2 (diff)
downloadstrongswan-709998e10634b98a0888a93b8b0586daa872e748.tar.bz2
strongswan-709998e10634b98a0888a93b8b0586daa872e748.tar.xz
Merge branch 'p-cscf'
This adds the p-cscf plugin that can request P-CSCF server addresses from an ePDG via IKEv2 (RFC 7651). Addresses of the same families as requested virtual IPs are requested if enabled in strongswan.conf for a particular connection. The plugin currently writes received addresses to the log.
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/Android.mk2
-rw-r--r--src/libcharon/Makefile.am7
-rw-r--r--src/libcharon/attributes/attributes.c16
-rw-r--r--src/libcharon/attributes/attributes.h3
-rw-r--r--src/libcharon/encoding/payloads/configuration_attribute.c2
-rw-r--r--src/libcharon/plugins/attr/attr_provider.c67
-rw-r--r--src/libcharon/plugins/p_cscf/Makefile.am19
-rw-r--r--src/libcharon/plugins/p_cscf/p_cscf_handler.c173
-rw-r--r--src/libcharon/plugins/p_cscf/p_cscf_handler.h49
-rw-r--r--src/libcharon/plugins/p_cscf/p_cscf_plugin.c101
-rw-r--r--src/libcharon/plugins/p_cscf/p_cscf_plugin.h43
11 files changed, 458 insertions, 24 deletions
diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk
index 8f8c96588..55e6bc58b 100644
--- a/src/libcharon/Android.mk
+++ b/src/libcharon/Android.mk
@@ -156,6 +156,8 @@ endif
LOCAL_SRC_FILES += $(call add_plugin, attr)
+LOCAL_SRC_FILES += $(call add_plugin, p-cscf)
+
LOCAL_SRC_FILES += $(call add_plugin, eap-aka)
LOCAL_SRC_FILES += $(call add_plugin, eap-aka-3gpp2)
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index 61e57c1cb..9f0707813 100644
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -489,6 +489,13 @@ if MONOLITHIC
endif
endif
+if USE_P_CSCF
+ SUBDIRS += plugins/p_cscf
+if MONOLITHIC
+ libcharon_la_LIBADD += plugins/p_cscf/libstrongswan-p-cscf.la
+endif
+endif
+
if USE_ANDROID_DNS
SUBDIRS += plugins/android_dns
if MONOLITHIC
diff --git a/src/libcharon/attributes/attributes.c b/src/libcharon/attributes/attributes.c
index 9fabcf4e4..0f28d55fa 100644
--- a/src/libcharon/attributes/attributes.c
+++ b/src/libcharon/attributes/attributes.c
@@ -17,7 +17,7 @@
#include "attributes.h"
-ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, HOME_AGENT_ADDRESS,
+ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, P_CSCF_IP6_ADDRESS,
"INTERNAL_IP4_ADDRESS",
"INTERNAL_IP4_NETMASK",
"INTERNAL_IP4_DNS",
@@ -36,8 +36,10 @@ ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, HOME_AGENT_
"MIP6_HOME_PREFIX",
"INTERNAL_IP6_LINK",
"INTERNAL_IP6_PREFIX",
- "HOME_AGENT_ADDRESS");
-ENUM_NEXT(configuration_attribute_type_names, XAUTH_TYPE, XAUTH_ANSWER, HOME_AGENT_ADDRESS,
+ "HOME_AGENT_ADDRESS",
+ "P_CSCF_IP4_ADDRESS",
+ "P_CSCF_IP6_ADDRESS");
+ENUM_NEXT(configuration_attribute_type_names, XAUTH_TYPE, XAUTH_ANSWER, P_CSCF_IP6_ADDRESS,
"XAUTH_TYPE",
"XAUTH_USER_NAME",
"XAUTH_USER_PASSWORD",
@@ -65,7 +67,7 @@ ENUM_NEXT(configuration_attribute_type_names, UNITY_BANNER, UNITY_DDNS_HOSTNAME,
"UNITY_DDNS_HOSTNAME");
ENUM_END(configuration_attribute_type_names, UNITY_DDNS_HOSTNAME);
-ENUM_BEGIN(configuration_attribute_type_short_names, INTERNAL_IP4_ADDRESS, HOME_AGENT_ADDRESS,
+ENUM_BEGIN(configuration_attribute_type_short_names, INTERNAL_IP4_ADDRESS, P_CSCF_IP6_ADDRESS,
"ADDR",
"MASK",
"DNS",
@@ -84,8 +86,10 @@ ENUM_BEGIN(configuration_attribute_type_short_names, INTERNAL_IP4_ADDRESS, HOME_
"MIP6HPFX",
"LINK6",
"PFX6",
- "HOA");
-ENUM_NEXT(configuration_attribute_type_short_names, XAUTH_TYPE, XAUTH_ANSWER, HOME_AGENT_ADDRESS,
+ "HOA",
+ "PCSCF4",
+ "PCSCF6");
+ENUM_NEXT(configuration_attribute_type_short_names, XAUTH_TYPE, XAUTH_ANSWER, P_CSCF_IP6_ADDRESS,
"X_TYPE",
"X_USER",
"X_PWD",
diff --git a/src/libcharon/attributes/attributes.h b/src/libcharon/attributes/attributes.h
index 5d1e9f9ba..dd1db4fc3 100644
--- a/src/libcharon/attributes/attributes.h
+++ b/src/libcharon/attributes/attributes.h
@@ -49,6 +49,9 @@ enum configuration_attribute_type_t {
INTERNAL_IP6_LINK = 17,
INTERNAL_IP6_PREFIX = 18,
HOME_AGENT_ADDRESS = 19,
+ /* RFC 7651 */
+ P_CSCF_IP4_ADDRESS = 20,
+ P_CSCF_IP6_ADDRESS = 21,
/* XAUTH attributes */
XAUTH_TYPE = 16520,
XAUTH_USER_NAME = 16521,
diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c
index 0bc94708f..4ecdf569d 100644
--- a/src/libcharon/encoding/payloads/configuration_attribute.c
+++ b/src/libcharon/encoding/payloads/configuration_attribute.c
@@ -132,6 +132,7 @@ METHOD(payload_t, verify, status_t,
case INTERNAL_IP4_NBNS:
case INTERNAL_ADDRESS_EXPIRY:
case INTERNAL_IP4_DHCP:
+ case P_CSCF_IP4_ADDRESS:
if (this->length_or_value != 0 && this->length_or_value != 4)
{
failed = TRUE;
@@ -160,6 +161,7 @@ METHOD(payload_t, verify, status_t,
case INTERNAL_IP6_DNS:
case INTERNAL_IP6_NBNS:
case INTERNAL_IP6_DHCP:
+ case P_CSCF_IP6_ADDRESS:
if (this->length_or_value != 0 && this->length_or_value != 16)
{
failed = TRUE;
diff --git a/src/libcharon/plugins/attr/attr_provider.c b/src/libcharon/plugins/attr/attr_provider.c
index cac0ae4bf..1de571c3f 100644
--- a/src/libcharon/plugins/attr/attr_provider.c
+++ b/src/libcharon/plugins/attr/attr_provider.c
@@ -54,6 +54,8 @@ struct attribute_entry_t {
configuration_attribute_type_t type;
/** attribute value */
chunk_t value;
+ /** associated IKE version */
+ ike_version_t ike;
};
/**
@@ -66,26 +68,51 @@ static void attribute_destroy(attribute_entry_t *this)
}
/**
+ * Data for attribute enumerator
+ */
+typedef struct {
+ rwlock_t *lock;
+ ike_version_t ike;
+} enumerator_data_t;
+
+/**
* convert enumerator value from attribute_entry
*/
-static bool attr_enum_filter(void *null, attribute_entry_t **in,
+static bool attr_enum_filter(enumerator_data_t *data, attribute_entry_t **in,
configuration_attribute_type_t *type, void* none, chunk_t *value)
{
- *type = (*in)->type;
- *value = (*in)->value;
- return TRUE;
+ if ((*in)->ike == IKE_ANY || (*in)->ike == data->ike)
+ {
+ *type = (*in)->type;
+ *value = (*in)->value;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+CALLBACK(attr_enum_destroy, void,
+ enumerator_data_t *data)
+{
+ data->lock->unlock(data->lock);
+ free(data);
}
METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
private_attr_provider_t *this, linked_list_t *pools,
ike_sa_t *ike_sa, linked_list_t *vips)
{
+ enumerator_data_t *data;
+
if (vips->get_count(vips))
{
+ INIT(data,
+ .lock = this->lock,
+ .ike = ike_sa->get_version(ike_sa),
+ );
this->lock->read_lock(this->lock);
return enumerator_create_filter(
this->attributes->create_enumerator(this->attributes),
- (void*)attr_enum_filter, this->lock, (void*)this->lock->unlock);
+ (void*)attr_enum_filter, data, attr_enum_destroy);
}
return enumerator_create_empty();
}
@@ -116,8 +143,6 @@ static void add_legacy_entry(private_attr_provider_t *this, char *key, int nr,
host = host_create_from_string(str, 0);
if (host)
{
- entry = malloc_thing(attribute_entry_t);
-
if (host->get_family(host) == AF_INET6)
{
switch (type)
@@ -132,8 +157,11 @@ static void add_legacy_entry(private_attr_provider_t *this, char *key, int nr,
break;
}
}
- entry->type = type;
- entry->value = chunk_clone(host->get_address(host));
+ INIT(entry,
+ .type = type,
+ .value = chunk_clone(host->get_address(host)),
+ .ike = IKE_ANY,
+ );
host->destroy(host);
DBG2(DBG_CFG, "loaded legacy entry attribute %N: %#B",
configuration_attribute_type_names, entry->type, &entry->value);
@@ -149,18 +177,20 @@ typedef struct {
char *name;
configuration_attribute_type_t v4;
configuration_attribute_type_t v6;
+ ike_version_t ike;
} attribute_type_key_t;
static attribute_type_key_t keys[] = {
- {"address", INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS},
- {"dns", INTERNAL_IP4_DNS, INTERNAL_IP6_DNS},
- {"nbns", INTERNAL_IP4_NBNS, INTERNAL_IP6_NBNS},
- {"dhcp", INTERNAL_IP4_DHCP, INTERNAL_IP6_DHCP},
- {"netmask", INTERNAL_IP4_NETMASK, INTERNAL_IP6_NETMASK},
- {"server", INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER},
- {"subnet", INTERNAL_IP4_SUBNET, INTERNAL_IP6_SUBNET},
- {"split-include", UNITY_SPLIT_INCLUDE, UNITY_SPLIT_INCLUDE},
- {"split-exclude", UNITY_LOCAL_LAN, UNITY_LOCAL_LAN},
+ {"address", INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS, IKE_ANY},
+ {"dns", INTERNAL_IP4_DNS, INTERNAL_IP6_DNS, IKE_ANY},
+ {"nbns", INTERNAL_IP4_NBNS, INTERNAL_IP6_NBNS, IKE_ANY},
+ {"dhcp", INTERNAL_IP4_DHCP, INTERNAL_IP6_DHCP, IKE_ANY},
+ {"netmask", INTERNAL_IP4_NETMASK, INTERNAL_IP6_NETMASK, IKE_ANY},
+ {"server", INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER, IKE_ANY},
+ {"subnet", INTERNAL_IP4_SUBNET, INTERNAL_IP6_SUBNET, IKE_ANY},
+ {"p-cscf", P_CSCF_IP4_ADDRESS, P_CSCF_IP6_ADDRESS, IKEV2},
+ {"split-include", UNITY_SPLIT_INCLUDE, UNITY_SPLIT_INCLUDE, IKEV1},
+ {"split-exclude", UNITY_LOCAL_LAN, UNITY_LOCAL_LAN, IKEV1},
};
/**
@@ -275,6 +305,7 @@ static void load_entries(private_attr_provider_t *this)
INIT(entry,
.type = type,
.value = data,
+ .ike = mapped ? mapped->ike : IKE_ANY,
);
DBG2(DBG_CFG, "loaded attribute %N: %#B",
configuration_attribute_type_names, entry->type, &entry->value);
diff --git a/src/libcharon/plugins/p_cscf/Makefile.am b/src/libcharon/plugins/p_cscf/Makefile.am
new file mode 100644
index 000000000..1e00a56a8
--- /dev/null
+++ b/src/libcharon/plugins/p_cscf/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = \
+ $(PLUGIN_CFLAGS)
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-p-cscf.la
+else
+plugin_LTLIBRARIES = libstrongswan-p-cscf.la
+endif
+
+libstrongswan_p_cscf_la_SOURCES = \
+ p_cscf_plugin.c p_cscf_plugin.h \
+ p_cscf_handler.c p_cscf_handler.h
+
+libstrongswan_p_cscf_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/p_cscf/p_cscf_handler.c b/src/libcharon/plugins/p_cscf/p_cscf_handler.c
new file mode 100644
index 000000000..76633845e
--- /dev/null
+++ b/src/libcharon/plugins/p_cscf/p_cscf_handler.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 Tobias Brunner
+ * 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 "p_cscf_handler.h"
+
+#include <networking/host.h>
+#include <utils/debug.h>
+
+typedef struct private_p_cscf_handler_t private_p_cscf_handler_t;
+
+/**
+ * Private data
+ */
+struct private_p_cscf_handler_t {
+
+ /**
+ * Public interface
+ */
+ p_cscf_handler_t public;
+};
+
+METHOD(attribute_handler_t, handle, bool,
+ private_p_cscf_handler_t *this, ike_sa_t *ike_sa,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ host_t *server;
+ int family = AF_INET6;
+
+ switch (type)
+ {
+ case P_CSCF_IP4_ADDRESS:
+ family = AF_INET;
+ /* fall-through */
+ case P_CSCF_IP6_ADDRESS:
+ server = host_create_from_chunk(family, data, 0);
+ if (!server)
+ {
+ DBG1(DBG_CFG, "received invalid P-CSCF server IP");
+ return FALSE;
+ }
+ DBG1(DBG_CFG, "received P-CSCF server IP %H", server);
+ server->destroy(server);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+METHOD(attribute_handler_t, release, void,
+ private_p_cscf_handler_t *this, ike_sa_t *ike_sa,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ switch (type)
+ {
+ case P_CSCF_IP4_ADDRESS:
+ case P_CSCF_IP6_ADDRESS:
+ /* nothing to do as we only log the server IPs */
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Data for attribute enumerator
+ */
+typedef struct {
+ enumerator_t public;
+ bool request_ipv4;
+ bool request_ipv6;
+} attr_enumerator_t;
+
+METHOD(enumerator_t, enumerate_attrs, bool,
+ attr_enumerator_t *this, configuration_attribute_type_t *type,
+ chunk_t *data)
+{
+ if (this->request_ipv4)
+ {
+ *type = P_CSCF_IP4_ADDRESS;
+ *data = chunk_empty;
+ this->request_ipv4 = FALSE;
+ return TRUE;
+ }
+ if (this->request_ipv6)
+ {
+ *type = P_CSCF_IP6_ADDRESS;
+ *data = chunk_empty;
+ this->request_ipv6 = FALSE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Check if the given host has a matching address family
+ */
+static bool is_family(host_t *host, int *family)
+{
+ return host->get_family(host) == *family;
+}
+
+/**
+ * Check if a list has a host of a given family
+ */
+static bool has_host_family(linked_list_t *list, int family)
+{
+ return list->find_first(list, (void*)is_family, NULL, &family) == SUCCESS;
+}
+
+METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
+ private_p_cscf_handler_t *this, ike_sa_t *ike_sa,
+ linked_list_t *vips)
+{
+ attr_enumerator_t *enumerator;
+
+ if (ike_sa->get_version(ike_sa) == IKEV1)
+ {
+ return enumerator_create_empty();
+ }
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_enumerate_attrs,
+ .destroy = (void*)free,
+ },
+ );
+ if (lib->settings->get_bool(lib->settings, "%s.plugins.p-cscf.enable.%s",
+ FALSE, lib->ns, ike_sa->get_name(ike_sa)))
+ {
+ enumerator->request_ipv4 = has_host_family(vips, AF_INET);
+ enumerator->request_ipv6 = has_host_family(vips, AF_INET6);
+ }
+ return &enumerator->public;
+}
+
+METHOD(p_cscf_handler_t, destroy, void,
+ private_p_cscf_handler_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+p_cscf_handler_t *p_cscf_handler_create()
+{
+ private_p_cscf_handler_t *this;
+
+ INIT(this,
+ .public = {
+ .handler = {
+ .handle = _handle,
+ .release = _release,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ },
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/p_cscf/p_cscf_handler.h b/src/libcharon/plugins/p_cscf/p_cscf_handler.h
new file mode 100644
index 000000000..ad4f1acce
--- /dev/null
+++ b/src/libcharon/plugins/p_cscf/p_cscf_handler.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 Tobias Brunner
+ * 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 p_cscf_handler p_cscf_handler
+ * @{ @ingroup p_cscf
+ */
+
+#ifndef P_CSCF_HANDLER_H_
+#define P_CSCF_HANDLER_H_
+
+#include <attributes/attribute_handler.h>
+
+typedef struct p_cscf_handler_t p_cscf_handler_t;
+
+/**
+ * Attribute handler for P-CSCF server addresses.
+ */
+struct p_cscf_handler_t {
+
+ /**
+ * Implements attribute_handler_t.
+ */
+ attribute_handler_t handler;
+
+ /**
+ * Destroy a p_cscf_handler_t.
+ */
+ void (*destroy)(p_cscf_handler_t *this);
+};
+
+/**
+ * Create an p_cscf_handler_t instance.
+ */
+p_cscf_handler_t *p_cscf_handler_create();
+
+#endif /** P_CSCF_HANDLER_H_ @}*/
diff --git a/src/libcharon/plugins/p_cscf/p_cscf_plugin.c b/src/libcharon/plugins/p_cscf/p_cscf_plugin.c
new file mode 100644
index 000000000..8e2bc727e
--- /dev/null
+++ b/src/libcharon/plugins/p_cscf/p_cscf_plugin.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2016 Tobias Brunner
+ * 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 "p_cscf_plugin.h"
+#include "p_cscf_handler.h"
+
+#include <daemon.h>
+
+typedef struct private_p_cscf_plugin_t private_p_cscf_plugin_t;
+
+/**
+ * Private data
+ */
+struct private_p_cscf_plugin_t {
+
+ /**
+ * Public interface
+ */
+ p_cscf_plugin_t public;
+
+ /**
+ * P-CSCF server address attribute handler
+ */
+ p_cscf_handler_t *handler;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_p_cscf_plugin_t *this)
+{
+ return "p-cscf";
+}
+
+/**
+ * Register handler
+ */
+static bool plugin_cb(private_p_cscf_plugin_t *this,
+ plugin_feature_t *feature, bool reg, void *cb_data)
+{
+ if (reg)
+ {
+ charon->attributes->add_handler(charon->attributes,
+ &this->handler->handler);
+ }
+ else
+ {
+ charon->attributes->remove_handler(charon->attributes,
+ &this->handler->handler);
+ }
+ return TRUE;
+}
+
+METHOD(plugin_t, get_features, int,
+ private_p_cscf_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
+ PLUGIN_PROVIDE(CUSTOM, "p-cscf"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_p_cscf_plugin_t *this)
+{
+ this->handler->destroy(this->handler);
+ free(this);
+}
+
+/**
+ * See header
+ */
+plugin_t *p_cscf_plugin_create()
+{
+ private_p_cscf_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ .handler = p_cscf_handler_create(),
+ );
+
+ return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/p_cscf/p_cscf_plugin.h b/src/libcharon/plugins/p_cscf/p_cscf_plugin.h
new file mode 100644
index 000000000..51b17674d
--- /dev/null
+++ b/src/libcharon/plugins/p_cscf/p_cscf_plugin.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 Tobias Brunner
+ * 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 p_cscf p_cscf
+ * @ingroup cplugins
+ *
+ * @defgroup p_cscf_plugin p_cscf_plugin
+ * @{ @ingroup p_cscf
+ */
+
+#ifndef P_CSCF_PLUGIN_H_
+#define P_CSCF_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct p_cscf_plugin_t p_cscf_plugin_t;
+
+/**
+ * Plugin that requests P-CSCF server addresses from an ePDG as specified
+ * in RFC 7651.
+ */
+struct p_cscf_plugin_t {
+
+ /**
+ * Implements plugin interface.
+ */
+ plugin_t plugin;
+};
+
+#endif /** P_CSCF_PLUGIN_H_ @}*/