aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS23
-rw-r--r--configure.in6
-rw-r--r--man/ipsec.conf.5.in23
-rw-r--r--man/strongswan.conf.5.in10
-rw-r--r--src/_updown/_updown.in14
-rw-r--r--src/charon-nm/nm/nm_handler.c16
-rw-r--r--src/charon-nm/nm/nm_service.c7
-rw-r--r--src/conftest/config.c2
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_attr.c2
-rw-r--r--src/frontends/android/jni/libandroidbridge/backend/android_service.c31
-rw-r--r--src/libcharon/Makefile.am7
-rw-r--r--src/libcharon/config/peer_cfg.c92
-rw-r--r--src/libcharon/config/peer_cfg.h37
-rw-r--r--src/libcharon/encoding/payloads/eap_payload.c167
-rw-r--r--src/libcharon/encoding/payloads/eap_payload.h22
-rw-r--r--src/libcharon/plugins/android/android_handler.c2
-rw-r--r--src/libcharon/plugins/android/android_service.c4
-rw-r--r--src/libcharon/plugins/dhcp/dhcp_provider.c27
-rw-r--r--src/libcharon/plugins/eap_dynamic/Makefile.am16
-rw-r--r--src/libcharon/plugins/eap_dynamic/eap_dynamic.c393
-rw-r--r--src/libcharon/plugins/eap_dynamic/eap_dynamic.h52
-rw-r--r--src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c62
-rw-r--r--src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h43
-rw-r--r--src/libcharon/plugins/eap_peap/eap_peap_peer.c5
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_accounting.c29
-rw-r--r--src/libcharon/plugins/eap_ttls/eap_ttls_peer.c5
-rw-r--r--src/libcharon/plugins/ha/ha_attribute.c6
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c20
-rw-r--r--src/libcharon/plugins/ha/ha_ike.c52
-rw-r--r--src/libcharon/plugins/ha/ha_tunnel.c2
-rw-r--r--src/libcharon/plugins/load_tester/load_tester_config.c11
-rw-r--r--src/libcharon/plugins/maemo/maemo_service.c4
-rw-r--r--src/libcharon/plugins/medcli/medcli_config.c3
-rw-r--r--src/libcharon/plugins/medsrv/medsrv_config.c1
-rw-r--r--src/libcharon/plugins/sql/sql_config.c18
-rw-r--r--src/libcharon/plugins/stroke/Makefile.am1
-rw-r--r--src/libcharon/plugins/stroke/stroke_attribute.c214
-rw-r--r--src/libcharon/plugins/stroke/stroke_attribute.h23
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c218
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.h4
-rw-r--r--src/libcharon/plugins/stroke/stroke_control.c49
-rw-r--r--src/libcharon/plugins/stroke/stroke_handler.c231
-rw-r--r--src/libcharon/plugins/stroke/stroke_handler.h64
-rw-r--r--src/libcharon/plugins/stroke/stroke_socket.c20
-rw-r--r--src/libcharon/plugins/uci/uci_config.c1
-rw-r--r--src/libcharon/plugins/updown/Makefile.am1
-rw-r--r--src/libcharon/plugins/updown/updown_handler.c243
-rw-r--r--src/libcharon/plugins/updown/updown_handler.h57
-rw-r--r--src/libcharon/plugins/updown/updown_listener.c112
-rw-r--r--src/libcharon/plugins/updown/updown_listener.h4
-rw-r--r--src/libcharon/plugins/updown/updown_plugin.c22
-rw-r--r--src/libcharon/processing/jobs/migrate_job.c15
-rw-r--r--src/libcharon/sa/child_sa.c21
-rw-r--r--src/libcharon/sa/child_sa.h4
-rw-r--r--src/libcharon/sa/eap/eap_manager.c40
-rw-r--r--src/libcharon/sa/eap/eap_manager.h12
-rw-r--r--src/libcharon/sa/ike_sa.c100
-rw-r--r--src/libcharon/sa/ike_sa.h10
-rw-r--r--src/libcharon/sa/ikev1/phase1.c30
-rw-r--r--src/libcharon/sa/ikev1/phase1.h16
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c28
-rw-r--r--src/libcharon/sa/ikev1/tasks/aggressive_mode.c6
-rw-r--r--src/libcharon/sa/ikev1/tasks/main_mode.c6
-rw-r--r--src/libcharon/sa/ikev1/tasks/mode_config.c131
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c44
-rw-r--r--src/libcharon/sa/ikev2/authenticators/eap_authenticator.c58
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c87
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_config.c141
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_mobike.c19
-rw-r--r--src/libhydra/attributes/attribute_handler.h6
-rw-r--r--src/libhydra/attributes/attribute_manager.c65
-rw-r--r--src/libhydra/attributes/attribute_manager.h14
-rw-r--r--src/libhydra/attributes/attribute_provider.h8
-rw-r--r--src/libhydra/attributes/mem_pool.c11
-rw-r--r--src/libhydra/attributes/mem_pool.h7
-rw-r--r--src/libhydra/plugins/attr/attr_provider.c6
-rw-r--r--src/libhydra/plugins/attr_sql/sql_attribute.c123
-rw-r--r--src/libhydra/plugins/resolve/resolve_handler.c77
-rw-r--r--src/libipsec/esp_context.c1
-rw-r--r--src/libipsec/ip_packet.c12
-rw-r--r--src/libstrongswan/eap/eap.c80
-rw-r--r--src/libstrongswan/eap/eap.h35
-rw-r--r--src/libstrongswan/utils/tun_device.c148
-rw-r--r--src/starter/args.c2
-rw-r--r--src/starter/cmp.c1
-rw-r--r--src/starter/confread.c79
-rw-r--r--src/starter/confread.h3
-rw-r--r--src/starter/keywords.h6
-rw-r--r--src/starter/keywords.txt4
-rw-r--r--src/starter/starterstroke.c2
-rw-r--r--src/stroke/stroke_msg.h2
91 files changed, 3096 insertions, 842 deletions
diff --git a/NEWS b/NEWS
index 3a308178b..de8afdb90 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,29 @@ strongswan-5.0.1
PAM directly anymore, but can use any XAuth backend to verify credentials,
including xauth-pam.
+- An EAP-Nak payload is returned by clients if the gateway requests an EAP
+ method that the client does not support. Clients can also request a specific
+ EAP method by configuring that method with leftauth.
+
+- The eap-dynamic plugin handles EAP-Nak payloads returned by clients and uses
+ these to select a different EAP method supported/requested by the client.
+ The plugin initially requests the first registered method or the first method
+ configured with charon.plugins.eap-dynamic.preferred.
+
+- The new left/rightdns options specify connection specific DNS servers to
+ request/respond in IKEv2 configuration payloads or IKEv2 mode config. leftdns
+ can be any (comma separated) combination of %config4 and %config6 to request
+ multiple servers, both for IPv4 and IPv6. rightdns takes a list of DNS server
+ IP addresses to return.
+
+- The left/rightsourceip options now accept multiple addresses or pools.
+ leftsourceip can be any (comma separated) combination of %config4, %config6
+ or fixed IP addresses to request. rightsourceip accepts multiple explicitly
+ specified or referenced named pools.
+
+- Multiple connections can now share a single address pool when they use the
+ same definition in one of the rightsourceip pools.
+
- The autotools build has been migrated to use a config.h header. strongSwan
development headers will get installed during "make install" if
--with-dev-headers has been passed to ./configure.
diff --git a/configure.in b/configure.in
index 2ab96e078..f233b0ab4 100644
--- a/configure.in
+++ b/configure.in
@@ -16,7 +16,7 @@ dnl ===========================
dnl initialize & set some vars
dnl ===========================
-AC_INIT(strongSwan,5.0.1dr3)
+AC_INIT(strongSwan,5.0.1dr4)
AM_INIT_AUTOMAKE(tar-ustar)
AC_CONFIG_MACRO_DIR([m4/config])
AC_CONFIG_HEADERS([config.h])
@@ -154,6 +154,7 @@ ARG_ENABL_SET([eap-tls], [enable EAP TLS authentication module.])
ARG_ENABL_SET([eap-ttls], [enable EAP TTLS authentication module.])
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-dynamic], [enable dynamic EAP proxy module.])
ARG_ENABL_SET([eap-radius], [enable RADIUS proxy authentication module.])
ARG_DISBL_SET([xauth-generic], [disable generic XAuth backend.])
ARG_ENABL_SET([xauth-eap], [enable XAuth backend using EAP methods to verify passwords.])
@@ -922,6 +923,7 @@ ADD_PLUGIN([eap-simaka-reauth], [c charon])
ADD_PLUGIN([eap-md5], [c charon nm])
ADD_PLUGIN([eap-gtc], [c charon nm])
ADD_PLUGIN([eap-mschapv2], [c charon nm])
+ADD_PLUGIN([eap-dynamic], [c charon])
ADD_PLUGIN([eap-radius], [c charon])
ADD_PLUGIN([eap-tls], [c charon nm])
ADD_PLUGIN([eap-ttls], [c charon nm])
@@ -1055,6 +1057,7 @@ AM_CONDITIONAL(USE_EAP_TLS, test x$eap_tls = xtrue)
AM_CONDITIONAL(USE_EAP_TTLS, test x$eap_ttls = xtrue)
AM_CONDITIONAL(USE_EAP_PEAP, test x$eap_peap = xtrue)
AM_CONDITIONAL(USE_EAP_TNC, test x$eap_tnc = xtrue)
+AM_CONDITIONAL(USE_EAP_DYNAMIC, test x$eap_dynamic = xtrue)
AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue)
AM_CONDITIONAL(USE_XAUTH_GENERIC, test x$xauth_generic = xtrue)
AM_CONDITIONAL(USE_XAUTH_EAP, test x$xauth_eap = xtrue)
@@ -1222,6 +1225,7 @@ AC_OUTPUT(
src/libcharon/Makefile
src/libcharon/plugins/eap_aka/Makefile
src/libcharon/plugins/eap_aka_3gpp2/Makefile
+ src/libcharon/plugins/eap_dynamic/Makefile
src/libcharon/plugins/eap_identity/Makefile
src/libcharon/plugins/eap_md5/Makefile
src/libcharon/plugins/eap_gtc/Makefile
diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in
index ca77ee7de..7c336c451 100644
--- a/man/ipsec.conf.5.in
+++ b/man/ipsec.conf.5.in
@@ -523,6 +523,7 @@ an optional EAP method can be appended. Currently defined methods are
.BR eap-sim ,
.BR eap-tls ,
.BR eap-ttls ,
+.BR eap-dynamic ,
and
.BR eap-radius .
Alternatively, IANA assigned EAP method numbers are accepted. Vendor specific
@@ -585,6 +586,16 @@ Comma separated list of certificate policy OIDs the peer's certificate must
have.
OIDs are specified using the numerical dotted representation.
.TP
+.BR leftdns " = <servers>"
+Comma separated list of DNS server addresses to exchange as configuration
+attributes. On the initiator, a server is a fixed IPv4 / IPv6 address, or
+.B %config4
+/
+.B %config6
+to request attributes without an address. On the responder,
+only fixed IPv4 /IPv6 addresses are allowed and define DNS servers assigned
+to the client.
+.TP
.BR leftfirewall " = yes | " no
whether the left participant is doing forwarding-firewalling
(including masquerading) using iptables for traffic from \fIleftsubnet\fR,
@@ -690,19 +701,19 @@ and
the latter meaning that the peer must send a certificate request payload in
order to get a certificate in return.
.TP
-.BR leftsourceip " = %config | %cfg | %modeconfig | %modecfg | <ip address>"
-The internal source IP to use in a tunnel, also known as virtual IP. If the
-value is one of the synonyms
+.BR leftsourceip " = %config4 | %config6 | <ip address>"
+Comma separated list of internal source IPs to use in a tunnel, also known as
+virtual IP. If the value is one of the synonyms
.BR %config ,
.BR %cfg ,
.BR %modeconfig ,
or
.BR %modecfg ,
-an address is requested from the peer.
+an address (from the tunnel address family) is requested from the peer.
.TP
.BR rightsourceip " = %config | <network>/<netmask> | %poolname"
-The internal source IP to use in a tunnel for the remote peer. If the
-value is
+Comma separated list of internal source IPs to use in a tunnel for the remote
+peer. If the value is
.B %config
on the responder side, the initiator must propose an address which is then
echoed back. Also supported are address pools expressed as
diff --git a/man/strongswan.conf.5.in b/man/strongswan.conf.5.in
index 4fba2344b..8df6cf1fa 100644
--- a/man/strongswan.conf.5.in
+++ b/man/strongswan.conf.5.in
@@ -303,6 +303,16 @@ enable loaded duplicheck plugin
.BR charon.plugins.eap-aka-3ggp2.seq_check
.TP
+.BR charon.plugins.eap-dynamic.preferred
+The preferred EAP method(s) to be used. If it is not given the first
+registered method will be used initially. If a comma separated list is given
+the methods are tried in the given order before trying the rest of the
+registered methods.
+.TP
+.BR charon.plugins.eap-dynamic.prefer_user " [no]"
+If enabled the EAP methods proposed in an EAP-Nak message sent by the peer are
+preferred over the methods registered locally.
+.TP
.BR charon.plugins.eap-gtc.backend " [pam]"
XAuth backend to be used for credential verification
.TP
diff --git a/src/_updown/_updown.in b/src/_updown/_updown.in
index 2c742c010..3a40e2110 100644
--- a/src/_updown/_updown.in
+++ b/src/_updown/_updown.in
@@ -73,8 +73,12 @@
# just the host, this will be 255.255.255.255.
#
# PLUTO_MY_SOURCEIP
-# if non-empty, then the source address for the route will be
-# set to this IP address.
+# PLUTO_MY_SOURCEIP4_$i
+# PLUTO_MY_SOURCEIP6_$i
+# contains IPv4/IPv6 virtual IP received from a responder,
+# $i enumerates from 1 to the number of IP per address family.
+# PLUTO_MY_SOURCEIP is a legacy variable and equals to the first
+# virtual IP, IPv4 or IPv6.
#
# PLUTO_MY_PROTOCOL
# is the IP protocol that will be transported.
@@ -128,6 +132,12 @@
# contains the remote UDP port in the case of ESP_IN_UDP
# encapsulation
#
+# PLUTO_DNS4_$i
+# PLUTO_DNS6_$i
+# contains IPv4/IPv6 DNS server attribute received from a
+# responder, $i enumerates from 1 to the number of servers per
+# address family.
+#
# define a minimum PATH environment in case it is not set
PATH="/sbin:/bin:/usr/sbin:/usr/bin:@sbindir@"
diff --git a/src/charon-nm/nm/nm_handler.c b/src/charon-nm/nm/nm_handler.c
index 408129ebe..28aa04b31 100644
--- a/src/charon-nm/nm/nm_handler.c
+++ b/src/charon-nm/nm/nm_handler.c
@@ -92,15 +92,17 @@ static bool enumerate_dns(enumerator_t *this,
}
METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
- private_nm_handler_t *this, identification_t *server, host_t *vip)
+ private_nm_handler_t *this, identification_t *server, linked_list_t *vips)
{
- if (vip && vip->get_family(vip) == AF_INET)
- { /* no IPv6 attributes yet */
- enumerator_t *enumerator = malloc_thing(enumerator_t);
- /* enumerate DNS attribute first ... */
- enumerator->enumerate = (void*)enumerate_dns;
- enumerator->destroy = (void*)free;
+ if (vips->get_count(vips))
+ {
+ enumerator_t *enumerator;
+ INIT(enumerator,
+ /* enumerate DNS attribute first ... */
+ .enumerate = (void*)enumerate_dns,
+ .destroy = (void*)free,
+ );
return enumerator;
}
return enumerator_create_empty();
diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c
index ccfa210a0..461837c0c 100644
--- a/src/charon-nm/nm/nm_service.c
+++ b/src/charon-nm/nm/nm_service.c
@@ -507,8 +507,11 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
600, 600, /* jitter, over 10min */
TRUE, FALSE, /* mobike, aggressive */
0, 0, /* DPD delay, timeout */
- virtual ? host_create_from_string("0.0.0.0", 0) : NULL,
- NULL, FALSE, NULL, NULL); /* pool, mediation */
+ FALSE, NULL, NULL); /* mediation */
+ if (virtual)
+ {
+ peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
+ }
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class);
auth->add(auth, AUTH_RULE_IDENTITY, user);
diff --git a/src/conftest/config.c b/src/conftest/config.c
index a3f23f3a4..cbc6ac05f 100644
--- a/src/conftest/config.c
+++ b/src/conftest/config.c
@@ -253,7 +253,7 @@ static peer_cfg_t *load_peer_config(private_config_t *this,
ike_cfg = load_ike_config(this, settings, config);
peer_cfg = peer_cfg_create(config, IKEV2, ike_cfg, CERT_ALWAYS_SEND,
UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, FALSE, 0, 0,
- NULL, NULL, FALSE, NULL, NULL);
+ FALSE, NULL, NULL);
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_attr.c b/src/frontends/android/jni/libandroidbridge/backend/android_attr.c
index e8c506950..f9e96a76c 100644
--- a/src/frontends/android/jni/libandroidbridge/backend/android_attr.c
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_attr.c
@@ -80,7 +80,7 @@ METHOD(enumerator_t, enumerate_dns, bool,
}
METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
- private_android_attr_t *this, identification_t *server, host_t *vip)
+ private_android_attr_t *this, identification_t *server, linked_list_t *vips)
{
enumerator_t *enumerator;
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/jni/libandroidbridge/backend/android_service.c
index 29b6d45af..f62aea0e8 100644
--- a/src/frontends/android/jni/libandroidbridge/backend/android_service.c
+++ b/src/frontends/android/jni/libandroidbridge/backend/android_service.c
@@ -250,21 +250,36 @@ static bool setup_tun_device(private_android_service_t *this,
ike_sa_t *ike_sa, child_sa_t *child_sa)
{
vpnservice_builder_t *builder;
+ enumerator_t *enumerator;
+ bool vip_found = FALSE;
host_t *vip;
int tunfd;
DBG1(DBG_DMN, "setting up TUN device for CHILD_SA %s{%u}",
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa));
- vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
- if (!vip || vip->is_anyaddr(vip))
+
+ builder = charonservice->get_vpnservice_builder(charonservice);
+
+ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
+ while (enumerator->enumerate(enumerator, &vip))
+ {
+ if (!vip->is_anyaddr(vip))
+ {
+ if (!builder->add_address(builder, vip))
+ {
+ break;
+ }
+ vip_found = TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!vip_found)
{
DBG1(DBG_DMN, "setting up TUN device failed, no virtual IP found");
return FALSE;
}
-
- builder = charonservice->get_vpnservice_builder(charonservice);
- if (!builder->add_address(builder, vip) ||
- !add_routes(builder, child_sa) ||
+ if (!add_routes(builder, child_sa) ||
!builder->set_mtu(builder, TUN_DEFAULT_MTU))
{
return FALSE;
@@ -442,8 +457,8 @@ static job_requeue_t initiate(private_android_service_t *this)
600, 600, /* jitter, over 10min */
TRUE, FALSE, /* mobike, aggressive */
0, 0, /* DPD delay, timeout */
- host_create_from_string("0.0.0.0", 0) /* virt */,
- NULL, FALSE, NULL, NULL); /* pool, mediation */
+ FALSE, NULL, NULL); /* mediation */
+ peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
/* local auth config */
if (streq("ikev2-eap", this->type))
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index eada68bf5..3869066a8 100644
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -316,6 +316,13 @@ if MONOLITHIC
endif
endif
+if USE_EAP_DYNAMIC
+ SUBDIRS += plugins/eap_dynamic
+if MONOLITHIC
+ libcharon_la_LIBADD += plugins/eap_dynamic/libstrongswan-eap-dynamic.la
+endif
+endif
+
if USE_EAP_RADIUS
SUBDIRS += plugins/eap_radius
if MONOLITHIC
diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c
index d16aedc79..59869eab2 100644
--- a/src/libcharon/config/peer_cfg.c
+++ b/src/libcharon/config/peer_cfg.c
@@ -141,14 +141,14 @@ struct private_peer_cfg_t {
u_int32_t dpd_timeout;
/**
- * virtual IP to use locally
+ * List of virtual IPs (host_t*) to request
*/
- host_t *virtual_ip;
+ linked_list_t *vips;
/**
- * pool to acquire configuration attributes from
+ * List of pool names to use for virtual IP lookup
*/
- char *pool;
+ linked_list_t *pools;
/**
* local authentication configs (rulesets)
@@ -409,16 +409,28 @@ METHOD(peer_cfg_t, get_dpd_timeout, u_int32_t,
return this->dpd_timeout;
}
-METHOD(peer_cfg_t, get_virtual_ip, host_t*,
+METHOD(peer_cfg_t, add_virtual_ip, void,
+ private_peer_cfg_t *this, host_t *vip)
+{
+ this->vips->insert_last(this->vips, vip);
+}
+
+METHOD(peer_cfg_t, create_virtual_ip_enumerator, enumerator_t*,
private_peer_cfg_t *this)
{
- return this->virtual_ip;
+ return this->vips->create_enumerator(this->vips);
}
-METHOD(peer_cfg_t, get_pool, char*,
+METHOD(peer_cfg_t, add_pool, void,
+ private_peer_cfg_t *this, char *name)
+{
+ this->pools->insert_last(this->pools, strdup(name));
+}
+
+METHOD(peer_cfg_t, create_pool_enumerator, enumerator_t*,
private_peer_cfg_t *this)
{
- return this->pool;
+ return this->pools->create_enumerator(this->pools);
}
METHOD(peer_cfg_t, add_auth_cfg, void,
@@ -521,6 +533,10 @@ static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other)
METHOD(peer_cfg_t, equals, bool,
private_peer_cfg_t *this, private_peer_cfg_t *other)
{
+ enumerator_t *e1, *e2;
+ host_t *vip1, *vip2;
+ char *pool1, *pool2;
+
if (this == other)
{
return TRUE;
@@ -530,6 +546,43 @@ METHOD(peer_cfg_t, equals, bool,
return FALSE;
}
+ if (this->vips->get_count(this->vips) != other->vips->get_count(other->vips))
+ {
+ return FALSE;
+ }
+ e1 = create_virtual_ip_enumerator(this);
+ e2 = create_virtual_ip_enumerator(other);
+ if (e1->enumerate(e1, &vip1) && e2->enumerate(e2, &vip2))
+ {
+ if (!vip1->ip_equals(vip1, vip2))
+ {
+ e1->destroy(e1);
+ e2->destroy(e2);
+ return FALSE;
+ }
+ }
+ e1->destroy(e1);
+ e2->destroy(e2);
+
+ if (this->pools->get_count(this->pools) !=
+ other->pools->get_count(other->pools))
+ {
+ return FALSE;
+ }
+ e1 = create_pool_enumerator(this);
+ e2 = create_pool_enumerator(other);
+ if (e1->enumerate(e1, &pool1) && e2->enumerate(e2, &pool2))
+ {
+ if (!streq(pool1, pool2))
+ {
+ e1->destroy(e1);
+ e2->destroy(e2);
+ return FALSE;
+ }
+ }
+ e1->destroy(e1);
+ e2->destroy(e2);
+
return (
this->ike_version == other->ike_version &&
this->cert_policy == other->cert_policy &&
@@ -541,11 +594,6 @@ METHOD(peer_cfg_t, equals, bool,
this->jitter_time == other->jitter_time &&
this->over_time == other->over_time &&
this->dpd == other->dpd &&
- (this->virtual_ip == other->virtual_ip ||
- (this->virtual_ip && other->virtual_ip &&
- this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) &&
- (this->pool == other->pool ||
- (this->pool && other->pool && streq(this->pool, other->pool))) &&
auth_cfg_equal(this, other)
#ifdef ME
&& this->mediation == other->mediation &&
@@ -572,18 +620,18 @@ METHOD(peer_cfg_t, destroy, void,
this->ike_cfg->destroy(this->ike_cfg);
this->child_cfgs->destroy_offset(this->child_cfgs,
offsetof(child_cfg_t, destroy));
- DESTROY_IF(this->virtual_ip);
this->local_auth->destroy_offset(this->local_auth,
offsetof(auth_cfg_t, destroy));
this->remote_auth->destroy_offset(this->remote_auth,
offsetof(auth_cfg_t, destroy));
+ this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
+ this->pools->destroy_function(this->pools, free);
#ifdef ME
DESTROY_IF(this->mediated_by);
DESTROY_IF(this->peer_id);
#endif /* ME */
this->mutex->destroy(this->mutex);
free(this->name);
- free(this->pool);
free(this);
}
}
@@ -597,8 +645,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version,
u_int32_t rekey_time, u_int32_t reauth_time,
u_int32_t jitter_time, u_int32_t over_time,
bool mobike, bool aggressive, u_int32_t dpd,
- u_int32_t dpd_timeout, host_t *virtual_ip,
- char *pool, bool mediation, peer_cfg_t *mediated_by,
+ u_int32_t dpd_timeout,
+ bool mediation, peer_cfg_t *mediated_by,
identification_t *peer_id)
{
private_peer_cfg_t *this;
@@ -631,8 +679,10 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version,
.use_aggressive = _use_aggressive,
.get_dpd = _get_dpd,
.get_dpd_timeout = _get_dpd_timeout,
- .get_virtual_ip = _get_virtual_ip,
- .get_pool = _get_pool,
+ .add_virtual_ip = _add_virtual_ip,
+ .create_virtual_ip_enumerator = _create_virtual_ip_enumerator,
+ .add_pool = _add_pool,
+ .create_pool_enumerator = _create_pool_enumerator,
.add_auth_cfg = _add_auth_cfg,
.create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
.equals = (void*)_equals,
@@ -660,8 +710,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version,
.aggressive = aggressive,
.dpd = dpd,
.dpd_timeout = dpd_timeout,
- .virtual_ip = virtual_ip,
- .pool = strdupnull(pool),
+ .vips = linked_list_create(),
+ .pools = linked_list_create(),
.local_auth = linked_list_create(),
.remote_auth = linked_list_create(),
.refcount = 1,
diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h
index 572153505..f65b91258 100644
--- a/src/libcharon/config/peer_cfg.h
+++ b/src/libcharon/config/peer_cfg.h
@@ -278,23 +278,34 @@ struct peer_cfg_t {
u_int32_t (*get_dpd_timeout) (peer_cfg_t *this);
/**
- * Get a virtual IP for the local peer.
+ * Add a virtual IP to request as initiator.
*
- * If no virtual IP should be used, NULL is returned. %any means to request
- * a virtual IP using configuration payloads. A specific address is also
- * used for a request and may be changed by the server.
+ * @param vip virtual IP to request, may be %any or %any6
+ */
+ void (*add_virtual_ip)(peer_cfg_t *this, host_t *vip);
+
+ /**
+ * Create an enumerator over virtual IPs to request.
+ *
+ * The returned enumerator enumerates over IPs added with add_virtual_ip().
+ *
+ * @return enumerator over host_t*
+ */
+ enumerator_t* (*create_virtual_ip_enumerator)(peer_cfg_t *this);
+
+ /**
+ * Add a pool name this configuration uses to select virtual IPs.
*
- * @param suggestion NULL, %any or specific
- * @return virtual IP, %any or NULL
+ * @param name pool name to use for virtual IP lookup
*/
- host_t* (*get_virtual_ip) (peer_cfg_t *this);
+ void (*add_pool)(peer_cfg_t *this, char *name);
/**
- * Get the name of the pool to acquire configuration attributes from.
+ * Create an enumerator over pool names of this config.
*
- * @return pool name, NULL if none defined
+ * @return enumerator over char*
*/
- char* (*get_pool)(peer_cfg_t *this);
+ enumerator_t* (*create_pool_enumerator)(peer_cfg_t *this);
#ifdef ME
/**
@@ -374,8 +385,6 @@ struct peer_cfg_t {
* @param aggressive use/accept aggressive mode with IKEv1
* @param dpd DPD check interval, 0 to disable
* @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies
- * @param virtual_ip virtual IP for local host, or NULL
- * @param pool pool name to get configuration attributes from, or NULL
* @param mediation TRUE if this is a mediation connection
* @param mediated_by peer_cfg_t of the mediation connection to mediate through
* @param peer_id ID that identifies our peer at the mediation server
@@ -387,8 +396,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version,
u_int32_t rekey_time, u_int32_t reauth_time,
u_int32_t jitter_time, u_int32_t over_time,
bool mobike, bool aggressive, u_int32_t dpd,
- u_int32_t dpd_timeout, host_t *virtual_ip,
- char *pool, bool mediation, peer_cfg_t *mediated_by,
+ u_int32_t dpd_timeout,
+ bool mediation, peer_cfg_t *mediated_by,
identification_t *peer_id);
#endif /** PEER_CFG_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c
index 1b9a5c802..dd2e25795 100644
--- a/src/libcharon/encoding/payloads/eap_payload.c
+++ b/src/libcharon/encoding/payloads/eap_payload.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -20,6 +21,7 @@
#include <daemon.h>
#include <eap/eap.h>
+#include <bio/bio_writer.h>
typedef struct private_eap_payload_t private_eap_payload_t;
@@ -217,28 +219,93 @@ METHOD(eap_payload_t, get_identifier, u_int8_t,
return 0;
}
+/**
+ * Get the current type at the given offset into this->data.
+ * @return the new offset or 0 if failed
+ */
+static size_t extract_type(private_eap_payload_t *this, size_t offset,
+ eap_type_t *type, u_int32_t *vendor)
+{
+ if (this->data.len > offset)
+ {
+ *vendor = 0;
+ *type = this->data.ptr[offset];
+ if (*type != EAP_EXPANDED)
+ {
+ return offset + 1;
+ }
+ if (this->data.len >= offset + 8)
+ {
+ *vendor = untoh32(this->data.ptr + offset) & 0x00FFFFFF;
+ *type = untoh32(this->data.ptr + offset + 4);
+ return offset + 8;
+ }
+ }
+ return 0;
+}
+
METHOD(eap_payload_t, get_type, eap_type_t,
private_eap_payload_t *this, u_int32_t *vendor)
{
eap_type_t type;
*vendor = 0;
- if (this->data.len > 4)
+ if (extract_type(this, 4, &type, vendor))
{
- type = this->data.ptr[4];
- if (type != EAP_EXPANDED)
- {
- return type;
- }
- if (this->data.len >= 12)
- {
- *vendor = untoh32(this->data.ptr + 4) & 0x00FFFFFF;
- return untoh32(this->data.ptr + 8);
- }
+ return type;
}
return 0;
}
+/**
+ * Type enumerator
+ */
+typedef struct {
+ /** public interface */
+ enumerator_t public;
+ /** payload */
+ private_eap_payload_t *payload;
+ /** current offset in the data */
+ size_t offset;
+} type_enumerator_t;
+
+METHOD(enumerator_t, enumerate_types, bool,
+ type_enumerator_t *this, eap_type_t *type, u_int32_t *vendor)
+{
+ this->offset = extract_type(this->payload, this->offset, type, vendor);
+ return this->offset;
+}
+
+METHOD(eap_payload_t, get_types, enumerator_t*,
+ private_eap_payload_t *this)
+{
+ type_enumerator_t *enumerator;
+ eap_type_t type;
+ u_int32_t vendor;
+ size_t offset;
+
+ offset = extract_type(this, 4, &type, &vendor);
+ if (offset && type == EAP_NAK)
+ {
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_enumerate_types,
+ .destroy = (void*)free,
+ },
+ .payload = this,
+ .offset = offset,
+ );
+ return &enumerator->public;
+ }
+ return enumerator_create_empty();
+}
+
+METHOD(eap_payload_t, is_expanded, bool,
+ private_eap_payload_t *this)
+{
+ return this->data.len > 4 ? this->data.ptr[4] == EAP_EXPANDED : FALSE;
+}
+
METHOD2(payload_t, eap_payload_t, destroy, void,
private_eap_payload_t *this)
{
@@ -270,6 +337,8 @@ eap_payload_t *eap_payload_create()
.get_code = _get_code,
.get_identifier = _get_identifier,
.get_type = _get_type,
+ .get_types = _get_types,
+ .is_expanded = _is_expanded,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
@@ -313,15 +382,81 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier)
return eap_payload_create_data(data);
}
+/**
+ * Write the given type either expanded or not
+ */
+static void write_type(bio_writer_t *writer, eap_type_t type, u_int32_t vendor,
+ bool expanded)
+{
+ if (expanded)
+ {
+ writer->write_uint8(writer, EAP_EXPANDED);
+ writer->write_uint24(writer, vendor);
+ writer->write_uint32(writer, type);
+ }
+ else
+ {
+ writer->write_uint8(writer, type);
+ }
+}
+
/*
* Described in header
*/
-eap_payload_t *eap_payload_create_nak(u_int8_t identifier)
+eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type,
+ u_int32_t vendor, bool expanded)
{
- chunk_t data;
+ enumerator_t *enumerator;
+ eap_type_t reg_type;
+ u_int32_t reg_vendor;
+ bio_writer_t *writer;
+ chunk_t length, data;
+ bool added_any = FALSE, found_vendor = FALSE;
+ eap_payload_t *payload;
+
+ writer = bio_writer_create(12);
+ writer->write_uint8(writer, EAP_RESPONSE);
+ writer->write_uint8(writer, identifier);
+ length = writer->skip(writer, 2);
+
+ write_type(writer, EAP_NAK, 0, expanded);
+
+ enumerator = charon->eap->create_enumerator(charon->eap, EAP_PEER);
+ while (enumerator->enumerate(enumerator, &reg_type, &reg_vendor))
+ {
+ if ((type && type != reg_type) ||
+ (type && vendor && vendor != reg_vendor))
+ { /* the preferred type is only sent if we actually find it */
+ continue;
+ }
+ if (!reg_vendor || expanded)
+ {
+ write_type(writer, reg_type, reg_vendor, expanded);
+ added_any = TRUE;
+ }
+ else if (reg_vendor)
+ { /* found vendor specifc method, but this is not an expanded Nak */
+ found_vendor = TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
- data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK);
- htoun16(data.ptr + 2, data.len);
- return eap_payload_create_data(data);
+ if (found_vendor)
+ { /* request an expanded authentication type */
+ write_type(writer, EAP_EXPANDED, 0, expanded);
+ added_any = TRUE;
+ }
+ if (!added_any)
+ { /* no methods added */
+ write_type(writer, 0, 0, expanded);
+ }
+
+ /* set length */
+ data = writer->get_buf(writer);
+ htoun16(length.ptr, data.len);
+
+ payload = eap_payload_create_data(data);
+ writer->destroy(writer);
+ return payload;
}
diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h
index 52bc7ac5e..e8ed1c5e7 100644
--- a/src/libcharon/encoding/payloads/eap_payload.h
+++ b/src/libcharon/encoding/payloads/eap_payload.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -82,6 +83,21 @@ struct eap_payload_t {
eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor);
/**
+ * Enumerate the EAP method types contained in an EAP-Nak (i.e. get_type()
+ * returns EAP_NAK).
+ *
+ * @return enumerator over (eap_type_t type, u_int32_t vendor)
+ */
+ enumerator_t* (*get_types) (eap_payload_t *this);
+
+ /**
+ * Check if the EAP method type is encoded in the Expanded Type format.
+ *
+ * @return TRUE if in Expanded Type format
+ */
+ bool (*is_expanded) (eap_payload_t *this);
+
+ /**
* Destroys an eap_payload_t object.
*/
void (*destroy) (eap_payload_t *this);
@@ -126,8 +142,12 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier);
* Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK.
*
* @param identifier EAP identifier to use in payload
+ * @param type preferred auth type, 0 to send all supported types
+ * @param vendor vendor identifier for auth type, 0 for default
+ * @param expanded TRUE to send an expanded Nak
* @return eap_payload_t object
*/
-eap_payload_t *eap_payload_create_nak(u_int8_t identifier);
+eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type,
+ u_int32_t vendor, bool expanded);
#endif /** EAP_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/plugins/android/android_handler.c b/src/libcharon/plugins/android/android_handler.c
index a53962f16..f1d3045ca 100644
--- a/src/libcharon/plugins/android/android_handler.c
+++ b/src/libcharon/plugins/android/android_handler.c
@@ -196,7 +196,7 @@ METHOD(enumerator_t, enumerate_dns, bool,
}
METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
- android_handler_t *this, identification_t *id, host_t *vip)
+ android_handler_t *this, identification_t *id, linked_list_t *vips)
{
enumerator_t *enumerator;
diff --git a/src/libcharon/plugins/android/android_service.c b/src/libcharon/plugins/android/android_service.c
index f2d8ddce9..81628b80a 100644
--- a/src/libcharon/plugins/android/android_service.c
+++ b/src/libcharon/plugins/android/android_service.c
@@ -275,8 +275,8 @@ static job_requeue_t initiate(private_android_service_t *this)
600, 600, /* jitter, over 10min */
TRUE, FALSE, /* mobike, aggressive */
0, 0, /* DPD delay, timeout */
- host_create_from_string("0.0.0.0", 0) /* virt */,
- NULL, FALSE, NULL, NULL); /* pool, mediation */
+ FALSE, NULL, NULL); /* mediation */
+ peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
diff --git a/src/libcharon/plugins/dhcp/dhcp_provider.c b/src/libcharon/plugins/dhcp/dhcp_provider.c
index a6a887780..e46cc4d90 100644
--- a/src/libcharon/plugins/dhcp/dhcp_provider.c
+++ b/src/libcharon/plugins/dhcp/dhcp_provider.c
@@ -84,7 +84,7 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
private_dhcp_provider_t *this, char *pool,
identification_t *id, host_t *requested)
{
- if (streq(pool, "dhcp"))
+ if (streq(pool, "dhcp") && requested->get_family(requested) == AF_INET)
{
dhcp_transaction_t *transaction, *old;
host_t *vip;
@@ -110,7 +110,7 @@ METHOD(attribute_provider_t, release_address, bool,
private_dhcp_provider_t *this, char *pool,
host_t *address, identification_t *id)
{
- if (streq(pool, "dhcp"))
+ if (streq(pool, "dhcp") && address->get_family(address) == AF_INET)
{
dhcp_transaction_t *transaction;
@@ -129,18 +129,25 @@ METHOD(attribute_provider_t, release_address, bool,
}
METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
- private_dhcp_provider_t *this, char *pool, identification_t *id,
- host_t *vip)
+ private_dhcp_provider_t *this, linked_list_t *pools, identification_t *id,
+ linked_list_t *vips)
{
- dhcp_transaction_t *transaction;
+ dhcp_transaction_t *transaction = NULL;
+ enumerator_t *enumerator;
+ host_t *vip;
- if (!vip)
+ this->mutex->lock(this->mutex);
+ enumerator = vips->create_enumerator(vips);
+ while (enumerator->enumerate(enumerator, &vip))
{
- return NULL;
+ transaction = this->transactions->get(this->transactions,
+ (void*)hash_id_host(id, vip));
+ if (transaction)
+ {
+ break;
+ }
}
- this->mutex->lock(this->mutex);
- transaction = this->transactions->get(this->transactions,
- (void*)hash_id_host(id, vip));
+ enumerator->destroy(enumerator);
if (!transaction)
{
this->mutex->unlock(this->mutex);
diff --git a/src/libcharon/plugins/eap_dynamic/Makefile.am b/src/libcharon/plugins/eap_dynamic/Makefile.am
new file mode 100644
index 000000000..0d07fbf35
--- /dev/null
+++ b/src/libcharon/plugins/eap_dynamic/Makefile.am
@@ -0,0 +1,16 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-eap-dynamic.la
+else
+plugin_LTLIBRARIES = libstrongswan-eap-dynamic.la
+endif
+
+libstrongswan_eap_dynamic_la_SOURCES = \
+ eap_dynamic_plugin.h eap_dynamic_plugin.c eap_dynamic.h eap_dynamic.c
+
+libstrongswan_eap_dynamic_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c
new file mode 100644
index 000000000..d24cbd128
--- /dev/null
+++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2012 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 "eap_dynamic.h"
+
+#include <daemon.h>
+#include <library.h>
+
+typedef struct private_eap_dynamic_t private_eap_dynamic_t;
+
+/**
+ * Private data of an eap_dynamic_t object.
+ */
+struct private_eap_dynamic_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ eap_dynamic_t public;
+
+ /**
+ * ID of the server
+ */
+ identification_t *server;
+
+ /**
+ * ID of the peer
+ */
+ identification_t *peer;
+
+ /**
+ * Our supported EAP types (as eap_vendor_type_t*)
+ */
+ linked_list_t *types;
+
+ /**
+ * EAP types supported by peer, if any
+ */
+ linked_list_t *other_types;
+
+ /**
+ * Prefer types sent by peer
+ */
+ bool prefer_peer;
+
+ /**
+ * The proxied EAP method
+ */
+ eap_method_t *method;
+};
+
+/**
+ * Compare two eap_vendor_type_t objects
+ */
+static bool entry_matches(eap_vendor_type_t *item, eap_vendor_type_t *other)
+{
+ return item->type == other->type && item->vendor == other->vendor;
+}
+
+/**
+ * Load the given EAP method
+ */
+static eap_method_t *load_method(private_eap_dynamic_t *this,
+ eap_type_t type, u_int32_t vendor)
+{
+ eap_method_t *method;
+
+ method = charon->eap->create_instance(charon->eap, type, vendor, EAP_SERVER,
+ this->server, this->peer);
+ if (!method)
+ {
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "loading vendor specific EAP method %d-%d failed",
+ type, vendor);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "loading %N method failed", eap_type_names, type);
+ }
+ }
+ return method;
+}
+
+/**
+ * Select the first method we can instantiate and is supported by both peers.
+ */
+static void select_method(private_eap_dynamic_t *this)
+{
+ eap_vendor_type_t *entry;
+ linked_list_t *outer = this->types, *inner = this->other_types;
+ char *who = "peer";
+
+ if (this->other_types && this->prefer_peer)
+ {
+ outer = this->other_types;
+ inner = this->types;
+ who = "us";
+ }
+
+ while (outer->remove_first(outer, (void*)&entry) == SUCCESS)
+ {
+ if (inner)
+ {
+ if (inner->find_first(inner, (void*)entry_matches,
+ NULL, entry) != SUCCESS)
+ {
+ if (entry->vendor)
+ {
+ DBG2(DBG_IKE, "proposed vendor specific EAP method %d-%d "
+ "not supported by %s, skipped", entry->type,
+ entry->vendor, who);
+ }
+ else
+ {
+ DBG2(DBG_IKE, "proposed %N method not supported by %s, "
+ "skipped", eap_type_names, entry->type, who);
+ }
+ free(entry);
+ continue;
+ }
+ }
+ this->method = load_method(this, entry->type, entry->vendor);
+ if (this->method)
+ {
+ if (entry->vendor)
+ {
+ DBG1(DBG_IKE, "vendor specific EAP method %d-%d selected",
+ entry->type, entry->vendor);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "%N method selected", eap_type_names,
+ entry->type);
+ }
+ free(entry);
+ break;
+ }
+ free(entry);
+ }
+}
+
+METHOD(eap_method_t, initiate, status_t,
+ private_eap_dynamic_t *this, eap_payload_t **out)
+{
+ if (!this->method)
+ {
+ select_method(this);
+ if (!this->method)
+ {
+ DBG1(DBG_IKE, "no supported EAP method found");
+ return FAILED;
+ }
+ }
+ return this->method->initiate(this->method, out);
+}
+
+METHOD(eap_method_t, process, status_t,
+ private_eap_dynamic_t *this, eap_payload_t *in, eap_payload_t **out)
+{
+ eap_type_t received_type, type;
+ u_int32_t received_vendor, vendor;
+
+ received_type = in->get_type(in, &received_vendor);
+ if (received_vendor == 0 && received_type == EAP_NAK)
+ {
+ enumerator_t *enumerator;
+
+ DBG1(DBG_IKE, "received %N, selecting a different EAP method",
+ eap_type_names, EAP_NAK);
+
+ if (this->other_types)
+ { /* we already received a Nak or a proper response before */
+ DBG1(DBG_IKE, "%N is not supported in this state", eap_type_names,
+ EAP_NAK);
+ return FAILED;
+ }
+
+ this->other_types = linked_list_create();
+ enumerator = in->get_types(in);
+ while (enumerator->enumerate(enumerator, &type, &vendor))
+ {
+ eap_vendor_type_t *entry;
+
+ if (!type)
+ {
+ DBG1(DBG_IKE, "peer does not support any other EAP methods");
+ enumerator->destroy(enumerator);
+ return FAILED;
+ }
+ INIT(entry,
+ .type = type,
+ .vendor = vendor,
+ );
+ this->other_types->insert_last(this->other_types, entry);
+ }
+ enumerator->destroy(enumerator);
+
+ /* restart with a different method */
+ this->method->destroy(this->method);
+ this->method = NULL;
+ return initiate(this, out);
+ }
+ if (!this->other_types)
+ { /* so we don't handle EAP-Naks later */
+ this->other_types = linked_list_create();
+ }
+ if (this->method)
+ {
+ return this->method->process(this->method, in, out);
+ }
+ return FAILED;
+}
+
+METHOD(eap_method_t, get_type, eap_type_t,
+ private_eap_dynamic_t *this, u_int32_t *vendor)
+{
+ if (this->method)
+ {
+ return this->method->get_type(this->method, vendor);
+ }
+ *vendor = 0;
+ return EAP_DYNAMIC;
+}
+
+METHOD(eap_method_t, get_msk, status_t,
+ private_eap_dynamic_t *this, chunk_t *msk)
+{
+ if (this->method)
+ {
+ return this->method->get_msk(this->method, msk);
+ }
+ return FAILED;
+}
+
+METHOD(eap_method_t, get_identifier, u_int8_t,
+ private_eap_dynamic_t *this)
+{
+ if (this->method)
+ {
+ return this->method->get_identifier(this->method);
+ }
+ return 0;
+}
+
+METHOD(eap_method_t, set_identifier, void,
+ private_eap_dynamic_t *this, u_int8_t identifier)
+{
+ if (this->method)
+ {
+ this->method->set_identifier(this->method, identifier);
+ }
+}
+
+METHOD(eap_method_t, is_mutual, bool,
+ private_eap_dynamic_t *this)
+{
+ if (this->method)
+ {
+ return this->method->is_mutual(this->method);
+ }
+ return FALSE;
+}
+
+METHOD(eap_method_t, destroy, void,
+ private_eap_dynamic_t *this)
+{
+ DESTROY_IF(this->method);
+ this->types->destroy_function(this->types, (void*)free);
+ DESTROY_FUNCTION_IF(this->other_types, (void*)free);
+ this->server->destroy(this->server);
+ this->peer->destroy(this->peer);
+ free(this);
+}
+
+/**
+ * Parse preferred EAP types
+ */
+static void handle_preferred_eap_types(private_eap_dynamic_t *this,
+ char *methods)
+{
+ enumerator_t *enumerator;
+ eap_vendor_type_t *type, *entry;
+ linked_list_t *preferred;
+ char *method;
+
+ /* parse preferred EAP methods, format: type[-vendor], ... */
+ preferred = linked_list_create();
+ enumerator = enumerator_create_token(methods, ",", " ");
+ while (enumerator->enumerate(enumerator, &method))
+ {
+ type = eap_vendor_type_from_string(method);
+ if (type)
+ {
+ preferred->insert_last(preferred, type);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = this->types->create_enumerator(this->types);
+ while (preferred->remove_last(preferred, (void**)&type) == SUCCESS)
+ { /* move (supported) types to the front, maintain the preferred order */
+ this->types->reset_enumerator(this->types, enumerator);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry_matches(entry, type))
+ {
+ this->types->remove_at(this->types, enumerator);
+ this->types->insert_first(this->types, entry);
+ break;
+ }
+ }
+ free(type);
+ }
+ enumerator->destroy(enumerator);
+ preferred->destroy(preferred);
+}
+
+/**
+ * Get all supported EAP methods
+ */
+static void get_supported_eap_types(private_eap_dynamic_t *this)
+{
+ enumerator_t *enumerator;
+ eap_type_t type;
+ u_int32_t vendor;
+
+ enumerator = charon->eap->create_enumerator(charon->eap, EAP_SERVER);
+ while (enumerator->enumerate(enumerator, &type, &vendor))
+ {
+ eap_vendor_type_t *entry;
+
+ INIT(entry,
+ .type = type,
+ .vendor = vendor,
+ );
+ this->types->insert_last(this->types, entry);
+ }
+ enumerator->destroy(enumerator);
+}
+
+/*
+ * Defined in header
+ */
+eap_dynamic_t *eap_dynamic_create(identification_t *server,
+ identification_t *peer)
+{
+ private_eap_dynamic_t *this;
+ char *preferred;
+
+ INIT(this,
+ .public = {
+ .interface = {
+ .initiate = _initiate,
+ .process = _process,
+ .get_type = _get_type,
+ .is_mutual = _is_mutual,
+ .get_msk = _get_msk,
+ .get_identifier = _get_identifier,
+ .set_identifier = _set_identifier,
+ .destroy = _destroy,
+ },
+ },
+ .peer = peer->clone(peer),
+ .server = server->clone(server),
+ .types = linked_list_create(),
+ .prefer_peer = lib->settings->get_bool(lib->settings,
+ "%s.plugins.eap-dynamic.prefer_peer", FALSE, charon->name),
+ );
+
+ /* get all supported EAP methods */
+ get_supported_eap_types(this);
+ /* move preferred methods to the front */
+ preferred = lib->settings->get_str(lib->settings,
+ "%s.plugins.eap-dynamic.preferred", NULL, charon->name);
+ if (preferred)
+ {
+ handle_preferred_eap_types(this, preferred);
+ }
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.h b/src/libcharon/plugins/eap_dynamic/eap_dynamic.h
new file mode 100644
index 000000000..35db4fa26
--- /dev/null
+++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 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 eap_dynamic_i eap_dynamic
+ * @{ @ingroup eap_dynamic
+ */
+
+#ifndef EAP_DYNAMIC_H_
+#define EAP_DYNAMIC_H_
+
+typedef struct eap_dynamic_t eap_dynamic_t;
+
+#include <sa/eap/eap_method.h>
+
+/**
+ * Implementation of the eap_method_t interface for a virtual EAP method that
+ * proxies other EAP methods and supports the selection of the actual method
+ * by the client.
+ */
+struct eap_dynamic_t {
+
+ /**
+ * Implemented eap_method_t interface
+ */
+ eap_method_t interface;
+};
+
+/**
+ * Create a dynamic EAP proxy serving any supported real method which is also
+ * supported (or selected) by the client.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return eap_dynamic_t object
+ */
+eap_dynamic_t *eap_dynamic_create(identification_t *server,
+ identification_t *peer);
+
+#endif /** EAP_DYNAMIC_H_ @}*/
diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c
new file mode 100644
index 000000000..d6f38b666
--- /dev/null
+++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 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 "eap_dynamic_plugin.h"
+
+#include "eap_dynamic.h"
+
+#include <daemon.h>
+
+METHOD(plugin_t, get_name, char*,
+ eap_dynamic_plugin_t *this)
+{
+ return "eap-dynamic";
+}
+
+METHOD(plugin_t, get_features, int,
+ eap_dynamic_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK(eap_method_register, eap_dynamic_create),
+ PLUGIN_PROVIDE(EAP_SERVER, EAP_DYNAMIC),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ eap_dynamic_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *eap_dynamic_plugin_create()
+{
+ eap_dynamic_plugin_t *this;
+
+ INIT(this,
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->plugin;
+}
+
diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h
new file mode 100644
index 000000000..9b124d8d2
--- /dev/null
+++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 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 eap_dynamic eap_dynamic
+ * @ingroup cplugins
+ *
+ * @defgroup eap_dynamic_plugin eap_dynamic_plugin
+ * @{ @ingroup eap_dynamic
+ */
+
+#ifndef EAP_DYNAMIC_PLUGIN_H_
+#define EAP_DYNAMIC_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct eap_dynamic_plugin_t eap_dynamic_plugin_t;
+
+/**
+ * EAP plugin that can use any supported EAP method the client supports or
+ * prefers to use.
+ */
+struct eap_dynamic_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** EAP_DYNAMIC_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.c b/src/libcharon/plugins/eap_peap/eap_peap_peer.c
index 72e201fb6..79fd667cb 100644
--- a/src/libcharon/plugins/eap_peap/eap_peap_peer.c
+++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.c
@@ -85,7 +85,7 @@ METHOD(tls_application_t, process, status_t,
default:
return FAILED;
}
-
+
in = eap_payload_create_data(data);
DBG3(DBG_IKE, "%B", &data);
chunk_free(&data);
@@ -151,7 +151,8 @@ METHOD(tls_application_t, process, status_t,
if (!this->ph2_method)
{
DBG1(DBG_IKE, "EAP method not supported");
- this->out = eap_payload_create_nak(in->get_identifier(in));
+ this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0,
+ in->is_expanded(in));
in->destroy(in);
return NEED_MORE;
}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
index 243c76304..7690cf9f8 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
@@ -149,6 +149,7 @@ static bool send_message(private_eap_radius_accounting_t *this,
*/
static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa)
{
+ enumerator_t *enumerator;
host_t *vip;
char buf[64];
chunk_t data;
@@ -157,17 +158,25 @@ static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa)
message->add(message, RAT_USER_NAME, chunk_create(buf, strlen(buf)));
snprintf(buf, sizeof(buf), "%#H", ike_sa->get_other_host(ike_sa));
message->add(message, RAT_CALLING_STATION_ID, chunk_create(buf, strlen(buf)));
- vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (vip && vip->get_family(vip) == AF_INET)
- {
- message->add(message, RAT_FRAMED_IP_ADDRESS, vip->get_address(vip));
- }
- if (vip && vip->get_family(vip) == AF_INET6)
+
+ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
+ while (enumerator->enumerate(enumerator, &vip))
{
- /* we currently assign /128 prefixes, only (reserved, length) */
- data = chunk_from_chars(0, 128);
- data = chunk_cata("cc", data, vip->get_address(vip));
- message->add(message, RAT_FRAMED_IPV6_PREFIX, data);
+ switch (vip->get_family(vip))
+ {
+ case AF_INET:
+ message->add(message, RAT_FRAMED_IP_ADDRESS,
+ vip->get_address(vip));
+ break;
+ case AF_INET6:
+ /* we currently assign /128 prefixes, only (reserved, length) */
+ data = chunk_from_chars(0, 128);
+ data = chunk_cata("cc", data, vip->get_address(vip));
+ message->add(message, RAT_FRAMED_IPV6_PREFIX, data);
+ break;
+ default:
+ break;
+ }
}
}
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
index 767111b3e..00a4da3f8 100644
--- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
+++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
@@ -138,7 +138,7 @@ METHOD(tls_application_t, process, status_t,
chunk_free(&avp_data);
}
while (eap_pos < eap_data.len);
-
+
in = eap_payload_create_data(eap_data);
chunk_free(&eap_data);
payload = (payload_t*)in;
@@ -192,7 +192,8 @@ METHOD(tls_application_t, process, status_t,
if (!this->method)
{
DBG1(DBG_IKE, "EAP method not supported");
- this->out = eap_payload_create_nak(in->get_identifier(in));
+ this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0,
+ in->is_expanded(in));
in->destroy(in);
return NEED_MORE;
}
diff --git a/src/libcharon/plugins/ha/ha_attribute.c b/src/libcharon/plugins/ha/ha_attribute.c
index 64bd2b8b7..f18c58b6a 100644
--- a/src/libcharon/plugins/ha/ha_attribute.c
+++ b/src/libcharon/plugins/ha/ha_attribute.c
@@ -181,6 +181,12 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
pool = get_pool(this, name);
if (pool)
{
+ if (pool->base->get_family(pool->base) !=
+ requested->get_family(requested))
+ {
+ this->mutex->unlock(this->mutex);
+ return NULL;
+ }
for (byte = 0; byte < pool->size / 8; byte++)
{
if (pool->mask[byte] != 0xFF)
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index 8b6ec9180..f07b4ea21 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -344,10 +344,10 @@ static void process_ike_update(private_ha_dispatcher_t *this,
ike_sa->set_other_host(ike_sa, value.host->clone(value.host));
break;
case HA_LOCAL_VIP:
- ike_sa->set_virtual_ip(ike_sa, TRUE, value.host);
+ ike_sa->add_virtual_ip(ike_sa, TRUE, value.host);
break;
case HA_REMOTE_VIP:
- ike_sa->set_virtual_ip(ike_sa, FALSE, value.host);
+ ike_sa->add_virtual_ip(ike_sa, FALSE, value.host);
received_vip = TRUE;
break;
case HA_PEER_ADDR:
@@ -413,18 +413,24 @@ static void process_ike_update(private_ha_dispatcher_t *this,
}
if (received_vip)
{
+ enumerator_t *pools, *vips;
host_t *vip;
char *pool;
peer_cfg = ike_sa->get_peer_cfg(ike_sa);
- vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (peer_cfg && vip)
+ if (peer_cfg)
{
- pool = peer_cfg->get_pool(peer_cfg);
- if (pool)
+ pools = peer_cfg->create_pool_enumerator(peer_cfg);
+ while (pools->enumerate(pools, &pool))
{
- this->attr->reserve(this->attr, pool, vip);
+ vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
+ while (vips->enumerate(vips, &vip))
+ {
+ this->attr->reserve(this->attr, pool, vip);
+ }
+ vips->destroy(vips);
}
+ pools->destroy(pools);
}
}
if (ike_sa->get_version(ike_sa) == IKEV1)
diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c
index d523e8919..442a3a23d 100644
--- a/src/libcharon/plugins/ha/ha_ike.c
+++ b/src/libcharon/plugins/ha/ha_ike.c
@@ -241,6 +241,34 @@ METHOD(listener_t, ike_state_change, bool,
return TRUE;
}
+/**
+ * Send a virtual IP sync message for remote VIPs
+ */
+static void sync_vips(private_ha_ike_t *this, ike_sa_t *ike_sa)
+{
+ ha_message_t *m = NULL;
+ enumerator_t *enumerator;
+ host_t *vip;
+
+ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
+ while (enumerator->enumerate(enumerator, &vip))
+ {
+ if (!m)
+ {
+ m = ha_message_create(HA_IKE_UPDATE);
+ m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
+ }
+ m->add_attribute(m, HA_REMOTE_VIP, vip);
+ }
+ enumerator->destroy(enumerator);
+
+ if (m)
+ {
+ this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
+ }
+}
+
METHOD(listener_t, message_hook, bool,
private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message,
bool incoming, bool plain)
@@ -276,18 +304,7 @@ METHOD(listener_t, message_hook, bool,
{ /* After IKE_SA has been established, sync peers virtual IP.
* We cannot sync it in the state_change hook, it is installed later.
* TODO: where to sync local VIP? */
- ha_message_t *m;
- host_t *vip;
-
- vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (vip)
- {
- m = ha_message_create(HA_IKE_UPDATE);
- m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
- m->add_attribute(m, HA_REMOTE_VIP, vip);
- this->socket->push(this->socket, m);
- this->cache->cache(this->cache, ike_sa, m);
- }
+ sync_vips(this, ike_sa);
}
}
if (!plain && ike_sa->get_version(ike_sa) == IKEV1)
@@ -296,7 +313,6 @@ METHOD(listener_t, message_hook, bool,
keymat_v1_t *keymat;
u_int32_t mid;
chunk_t iv;
- host_t *vip;
mid = message->get_message_id(message);
if (mid == 0)
@@ -313,15 +329,7 @@ METHOD(listener_t, message_hook, bool,
}
if (!incoming && message->get_exchange_type(message) == TRANSACTION)
{
- vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (vip)
- {
- m = ha_message_create(HA_IKE_UPDATE);
- m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
- m->add_attribute(m, HA_REMOTE_VIP, vip);
- this->socket->push(this->socket, m);
- this->cache->cache(this->cache, ike_sa, m);
- }
+ sync_vips(this, ike_sa);
}
}
if (plain && ike_sa->get_version(ike_sa) == IKEV1 &&
diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c
index ad458caad..541dd9313 100644
--- a/src/libcharon/plugins/ha/ha_tunnel.c
+++ b/src/libcharon/plugins/ha/ha_tunnel.c
@@ -209,7 +209,7 @@ static void setup_tunnel(private_ha_tunnel_t *this,
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
peer_cfg = peer_cfg_create("ha", IKEV2, ike_cfg, CERT_NEVER_SEND,
UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30,
- 0, NULL, NULL, FALSE, NULL, NULL);
+ 0, FALSE, NULL, NULL);
auth_cfg = auth_cfg_create();
auth_cfg->add(auth_cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c
index f5da8b892..735f17985 100644
--- a/src/libcharon/plugins/load_tester/load_tester_config.c
+++ b/src/libcharon/plugins/load_tester/load_tester_config.c
@@ -268,8 +268,15 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num)
FALSE, FALSE, /* mobike, aggressive mode */
this->dpd_delay, /* dpd_delay */
this->dpd_timeout, /* dpd_timeout */
- this->vip ? this->vip->clone(this->vip) : NULL,
- this->pool, FALSE, NULL, NULL);
+ FALSE, NULL, NULL);
+ if (this->vip)
+ {
+ peer_cfg->add_virtual_ip(peer_cfg, this->vip->clone(this->vip));
+ }
+ if (this->pool)
+ {
+ peer_cfg->add_pool(peer_cfg, this->pool);
+ }
if (num)
{ /* initiator */
generate_auth_cfg(this, this->initiator_auth, peer_cfg, TRUE, num);
diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c
index f638a81b7..cb2fc9ebb 100644
--- a/src/libcharon/plugins/maemo/maemo_service.c
+++ b/src/libcharon/plugins/maemo/maemo_service.c
@@ -335,8 +335,8 @@ static gboolean initiate_connection(private_maemo_service_t *this,
600, 600, /* jitter, over 10min */
TRUE, FALSE, /* mobike, aggressive */
0, 0, /* DPD delay, timeout */
- host_create_from_string("0.0.0.0", 0) /* virt */,
- NULL, FALSE, NULL, NULL); /* pool, mediation */
+ FALSE, NULL, NULL); /* mediation */
+ peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c
index 829c8f05e..a1825effc 100644
--- a/src/libcharon/plugins/medcli/medcli_config.c
+++ b/src/libcharon/plugins/medcli/medcli_config.c
@@ -129,7 +129,6 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
this->rekey*5, this->rekey*3, /* jitter, overtime */
TRUE, FALSE, /* mobike, aggressive */
this->dpd, 0, /* DPD delay, timeout */
- NULL, NULL, /* vip, pool */
TRUE, NULL, NULL); /* mediation, med by, peer id */
e->destroy(e);
@@ -167,7 +166,6 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
this->rekey*5, this->rekey*3, /* jitter, overtime */
TRUE, FALSE, /* mobike, aggressive */
this->dpd, 0, /* DPD delay, timeout */
- NULL, NULL, /* vip, pool */
FALSE, med_cfg, /* mediation, med by */
identification_create_from_encoding(ID_KEY_ID, other));
@@ -243,7 +241,6 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool,
this->rekey*5, this->rekey*3, /* jitter, overtime */
TRUE, FALSE, /* mobike, aggressive */
this->dpd, 0, /* DPD delay, timeout */
- NULL, NULL, /* vip, pool */
FALSE, NULL, NULL); /* mediation, med by, peer id */
auth = auth_cfg_create();
diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c
index ebc142de2..ff33c53e1 100644
--- a/src/libcharon/plugins/medsrv/medsrv_config.c
+++ b/src/libcharon/plugins/medsrv/medsrv_config.c
@@ -94,7 +94,6 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
this->rekey*5, this->rekey*3, /* jitter, overtime */
TRUE, FALSE, /* mobike, aggressiv */
this->dpd, 0, /* DPD delay, timeout */
- NULL, NULL, /* vip, pool */
TRUE, NULL, NULL); /* mediation, med by, peer id */
e->destroy(e);
diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c
index 890077157..c614c679e 100644
--- a/src/libcharon/plugins/sql/sql_config.c
+++ b/src/libcharon/plugins/sql/sql_config.c
@@ -333,6 +333,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
mediation, mediated_by, p_type;
chunk_t l_data, r_data, p_data;
char *name, *virtual, *pool;
+ enumerator_t *enumerator;
while (e->enumerate(e,
&id, &name, &ike_cfg, &l_type, &l_data, &r_type, &r_data,
@@ -371,8 +372,23 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
peer_cfg = peer_cfg_create(
name, IKEV2, ike, cert_policy, uniqueid,
keyingtries, rekeytime, reauthtime, jitter, overtime,
- mobike, FALSE, dpd_delay, 0, vip, pool,
+ mobike, FALSE, dpd_delay, 0,
mediation, mediated_cfg, peer_id);
+ if (vip)
+ {
+ peer_cfg->add_virtual_ip(peer_cfg, vip);
+ }
+ if (pool)
+ {
+ /* attr-sql used comma separated pools, but we now completely
+ * support multiple pools directly. Support old SQL configs: */
+ enumerator = enumerator_create_token(pool, ",", " ");
+ while (enumerator->enumerate(enumerator, &pool))
+ {
+ peer_cfg->add_pool(peer_cfg, pool);
+ }
+ enumerator->destroy(enumerator);
+ }
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method);
auth->add(auth, AUTH_RULE_IDENTITY, local_id);
diff --git a/src/libcharon/plugins/stroke/Makefile.am b/src/libcharon/plugins/stroke/Makefile.am
index e561224e9..cebcd984f 100644
--- a/src/libcharon/plugins/stroke/Makefile.am
+++ b/src/libcharon/plugins/stroke/Makefile.am
@@ -21,6 +21,7 @@ libstrongswan_stroke_la_SOURCES = \
stroke_cred.h stroke_cred.c \
stroke_ca.h stroke_ca.c \
stroke_attribute.h stroke_attribute.c \
+ stroke_handler.h stroke_handler.c \
stroke_list.h stroke_list.c
libstrongswan_stroke_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/stroke/stroke_attribute.c b/src/libcharon/plugins/stroke/stroke_attribute.c
index 1e4615e12..3e012230a 100644
--- a/src/libcharon/plugins/stroke/stroke_attribute.c
+++ b/src/libcharon/plugins/stroke/stroke_attribute.c
@@ -17,7 +17,6 @@
#include "stroke_attribute.h"
#include <daemon.h>
-#include <attributes/mem_pool.h>
#include <utils/linked_list.h>
#include <threading/rwlock.h>
@@ -39,12 +38,37 @@ struct private_stroke_attribute_t {
linked_list_t *pools;
/**
+ * List of connection specific attributes, as attributes_t
+ */
+ linked_list_t *attrs;
+
+ /**
* rwlock to lock access to pools
*/
rwlock_t *lock;
};
/**
+ * Attributes assigned to a connection
+ */
+typedef struct {
+ /** name of the connection */
+ char *name;
+ /** list of DNS attributes, as host_t */
+ linked_list_t *dns;
+} attributes_t;
+
+/**
+ * Destroy an attributes_t entry
+ */
+static void attributes_destroy(attributes_t *this)
+{
+ this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+ free(this->name);
+ free(this);
+}
+
+/**
* find a pool by name
*/
static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
@@ -66,11 +90,12 @@ static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
}
METHOD(attribute_provider_t, acquire_address, host_t*,
- private_stroke_attribute_t *this, char *name, identification_t *id,
- host_t *requested)
+ private_stroke_attribute_t *this, char *name, identification_t *id,
+ host_t *requested)
{
mem_pool_t *pool;
host_t *addr = NULL;
+
this->lock->read_lock(this->lock);
pool = find_pool(this, name);
if (pool)
@@ -82,11 +107,12 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
}
METHOD(attribute_provider_t, release_address, bool,
- private_stroke_attribute_t *this, char *name, host_t *address,
- identification_t *id)
+ private_stroke_attribute_t *this, char *name, host_t *address,
+ identification_t *id)
{
mem_pool_t *pool;
bool found = FALSE;
+
this->lock->read_lock(this->lock);
pool = find_pool(this, name);
if (pool)
@@ -97,56 +123,162 @@ METHOD(attribute_provider_t, release_address, bool,
return found;
}
-METHOD(stroke_attribute_t, add_pool, void,
- private_stroke_attribute_t *this, stroke_msg_t *msg)
+/**
+ * Filter function to convert host to DNS configuration attributes
+ */
+static bool attr_filter(void *lock, host_t **in,
+ configuration_attribute_type_t *type,
+ void *dummy, chunk_t *data)
{
- if (msg->add_conn.other.sourceip_mask)
+ host_t *host = *in;
+
+ switch (host->get_family(host))
{
- mem_pool_t *pool;
- host_t *base = NULL;
- u_int32_t bits = 0;
+ case AF_INET:
+ *type = INTERNAL_IP4_DNS;
+ break;
+ case AF_INET6:
+ *type = INTERNAL_IP6_DNS;
+ break;
+ default:
+ return FALSE;
+ }
+ *data = host->get_address(host);
+ return TRUE;
+}
- /* if %config, add an empty pool, otherwise */
- if (msg->add_conn.other.sourceip)
+METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
+ private_stroke_attribute_t *this, linked_list_t *pools,
+ identification_t *id, linked_list_t *vips)
+{
+ ike_sa_t *ike_sa;
+ peer_cfg_t *peer_cfg;
+ enumerator_t *enumerator;
+ attributes_t *attr;
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa)
+ {
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ this->lock->read_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
{
- DBG1(DBG_CFG, "adding virtual IP address pool '%s': %s/%d",
- msg->add_conn.name, msg->add_conn.other.sourceip,
- msg->add_conn.other.sourceip_mask);
- base = host_create_from_string(msg->add_conn.other.sourceip, 0);
- if (!base)
+ if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
{
- DBG1(DBG_CFG, "virtual IP address invalid, discarded");
- return;
+ enumerator->destroy(enumerator);
+ return enumerator_create_filter(
+ attr->dns->create_enumerator(attr->dns),
+ (void*)attr_filter, this->lock,
+ (void*)this->lock->unlock);
}
- bits = msg->add_conn.other.sourceip_mask;
}
- pool = mem_pool_create(msg->add_conn.name, base, bits);
- DESTROY_IF(base);
-
- this->lock->write_lock(this->lock);
- this->pools->insert_last(this->pools, pool);
+ enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
}
+ return enumerator_create_empty();
}
-METHOD(stroke_attribute_t, del_pool, void,
- private_stroke_attribute_t *this, stroke_msg_t *msg)
+METHOD(stroke_attribute_t, add_pool, void,
+ private_stroke_attribute_t *this, mem_pool_t *pool)
{
enumerator_t *enumerator;
- mem_pool_t *pool;
+ mem_pool_t *current;
+ host_t *base;
+ int size;
+
+ base = pool->get_base(pool);
+ size = pool->get_size(pool);
this->lock->write_lock(this->lock);
+
enumerator = this->pools->create_enumerator(this->pools);
- while (enumerator->enumerate(enumerator, &pool))
+ while (enumerator->enumerate(enumerator, &current))
{
- if (streq(msg->del_conn.name, pool->get_name(pool)))
+ if (base && current->get_base(current) &&
+ base->ip_equals(base, current->get_base(current)) &&
+ size == current->get_size(current))
{
- this->pools->remove_at(this->pools, enumerator);
pool->destroy(pool);
+ pool = NULL;
+ DBG1(DBG_CFG, "reusing virtual IP address pool %H/%d", base, size);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (pool)
+ {
+ if (base)
+ {
+ DBG1(DBG_CFG, "adding virtual IP address pool %H/%d", base, size);
+ }
+ this->pools->insert_last(this->pools, pool);
+ }
+
+ this->lock->unlock(this->lock);
+}
+
+METHOD(stroke_attribute_t, add_dns, void,
+ private_stroke_attribute_t *this, stroke_msg_t *msg)
+{
+ if (msg->add_conn.other.dns)
+ {
+ enumerator_t *enumerator;
+ attributes_t *attr = NULL;
+ host_t *host;
+ char *token;
+
+ enumerator = enumerator_create_token(msg->add_conn.other.dns, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ host = host_create_from_string(token, 0);
+ if (host)
+ {
+ if (!attr)
+ {
+ INIT(attr,
+ .name = strdup(msg->add_conn.name),
+ .dns = linked_list_create(),
+ );
+ }
+ attr->dns->insert_last(attr->dns, host);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (attr)
+ {
+ this->lock->write_lock(this->lock);
+ this->attrs->insert_last(this->attrs, attr);
+ this->lock->unlock(this->lock);
+ }
+ }
+}
+
+METHOD(stroke_attribute_t, del_dns, void,
+ private_stroke_attribute_t *this, stroke_msg_t *msg)
+{
+ enumerator_t *enumerator;
+ attributes_t *attr;
+
+ this->lock->write_lock(this->lock);
+
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (streq(msg->del_conn.name, attr->name))
+ {
+ this->attrs->remove_at(this->attrs, enumerator);
+ attributes_destroy(attr);
break;
}
}
enumerator->destroy(enumerator);
+
this->lock->unlock(this->lock);
}
@@ -158,6 +290,11 @@ static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name,
void *d3, u_int *offline)
{
mem_pool_t *pool = *poolp;
+
+ if (pool->get_size(pool) == 0)
+ {
+ return FALSE;
+ }
*name = pool->get_name(pool);
*size = pool->get_size(pool);
*online = pool->get_online(pool);
@@ -166,7 +303,7 @@ static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name,
}
METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*,
- private_stroke_attribute_t *this)
+ private_stroke_attribute_t *this)
{
this->lock->read_lock(this->lock);
return enumerator_create_filter(this->pools->create_enumerator(this->pools),
@@ -175,7 +312,7 @@ METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*,
}
METHOD(stroke_attribute_t, create_lease_enumerator, enumerator_t*,
- private_stroke_attribute_t *this, char *name)
+ private_stroke_attribute_t *this, char *name)
{
mem_pool_t *pool;
this->lock->read_lock(this->lock);
@@ -190,10 +327,11 @@ METHOD(stroke_attribute_t, create_lease_enumerator, enumerator_t*,
}
METHOD(stroke_attribute_t, destroy, void,
- private_stroke_attribute_t *this)
+ private_stroke_attribute_t *this)
{
this->lock->destroy(this->lock);
this->pools->destroy_offset(this->pools, offsetof(mem_pool_t, destroy));
+ this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
free(this);
}
@@ -209,15 +347,17 @@ stroke_attribute_t *stroke_attribute_create()
.provider = {
.acquire_address = _acquire_address,
.release_address = _release_address,
- .create_attribute_enumerator = enumerator_create_empty,
+ .create_attribute_enumerator = _create_attribute_enumerator,
},
.add_pool = _add_pool,
- .del_pool = _del_pool,
+ .add_dns = _add_dns,
+ .del_dns = _del_dns,
.create_pool_enumerator = _create_pool_enumerator,
.create_lease_enumerator = _create_lease_enumerator,
.destroy = _destroy,
},
.pools = linked_list_create(),
+ .attrs = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
diff --git a/src/libcharon/plugins/stroke/stroke_attribute.h b/src/libcharon/plugins/stroke/stroke_attribute.h
index 249a9899b..f1b9d135b 100644
--- a/src/libcharon/plugins/stroke/stroke_attribute.h
+++ b/src/libcharon/plugins/stroke/stroke_attribute.h
@@ -23,6 +23,7 @@
#include <stroke_msg.h>
#include <attributes/attribute_provider.h>
+#include <attributes/mem_pool.h>
typedef struct stroke_attribute_t stroke_attribute_t;
@@ -37,18 +38,28 @@ struct stroke_attribute_t {
attribute_provider_t provider;
/**
- * Add a virtual IP address pool.
+ * Add a memory pool to this virtual IP backend.
*
- * @param msg stroke message
+ * The pool gets owned by the provider, or destroyed if such a pool
+ * is already registered.
+ *
+ * @param pool virtual IP pool to add
+ */
+ void (*add_pool)(stroke_attribute_t *this, mem_pool_t *pool);
+
+ /**
+ * Add connection specific DNS servers.
+ *
+ * @param msg stroke add message
*/
- void (*add_pool)(stroke_attribute_t *this, stroke_msg_t *msg);
+ void (*add_dns)(stroke_attribute_t *this, stroke_msg_t *msg);
/**
- * Remove a virtual IP address pool.
+ * Remove connection specific DNS servers.
*
- * @param msg stroke message
+ * @param msg stroke del message
*/
- void (*del_pool)(stroke_attribute_t *this, stroke_msg_t *msg);
+ void (*del_dns)(stroke_attribute_t *this, stroke_msg_t *msg);
/**
* Create an enumerator over installed pools.
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index bf93f2c34..e3c78f750 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -52,6 +52,11 @@ struct private_stroke_config_t {
* credentials
*/
stroke_cred_t *cred;
+
+ /**
+ * Virtual IP pool / DNS backend
+ */
+ stroke_attribute_t *attributes;
};
METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
@@ -563,51 +568,20 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
}
else if (strneq(auth, "eap", 3))
{
- enumerator_t *enumerator;
- char *str;
- int i = 0, type = 0, vendor;
+ eap_vendor_type_t *type;
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
- /* parse EAP string, format: eap[-type[-vendor]] */
- enumerator = enumerator_create_token(auth, "-", " ");
- while (enumerator->enumerate(enumerator, &str))
+ type = eap_vendor_type_from_string(auth);
+ if (type)
{
- switch (i)
+ cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type);
+ if (type->vendor)
{
- case 1:
- type = eap_type_from_string(str);
- if (!type)
- {
- type = atoi(str);
- if (!type)
- {
- DBG1(DBG_CFG, "unknown EAP method: %s", str);
- break;
- }
- }
- cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
- break;
- case 2:
- if (type)
- {
- vendor = atoi(str);
- if (vendor)
- {
- cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
- }
- else
- {
- DBG1(DBG_CFG, "unknown EAP vendor: %s", str);
- }
- }
- break;
- default:
- break;
+ cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor);
}
- i++;
+ free(type);
}
- enumerator->destroy(enumerator);
if (msg->add_conn.eap_identity)
{
@@ -649,7 +623,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
{
identification_t *peer_id = NULL;
peer_cfg_t *mediated_by = NULL;
- host_t *vip = NULL;
unique_policy_t unique;
u_int32_t rekey = 0, reauth = 0, over, jitter;
peer_cfg_t *peer_cfg;
@@ -708,49 +681,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
{
rekey = msg->add_conn.rekey.ike_lifetime - over;
}
- if (msg->add_conn.me.sourceip_mask)
- {
- if (msg->add_conn.me.sourceip)
- {
- vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
- }
- if (!vip)
- { /* if it is set to something like %poolname, request an address */
- if (msg->add_conn.me.subnets)
- { /* use the same family as in local subnet, if any */
- if (strchr(msg->add_conn.me.subnets, '.'))
- {
- vip = host_create_any(AF_INET);
- }
- else
- {
- vip = host_create_any(AF_INET6);
- }
- }
- else if (msg->add_conn.other.subnets)
- { /* use the same family as in remote subnet, if any */
- if (strchr(msg->add_conn.other.subnets, '.'))
- {
- vip = host_create_any(AF_INET);
- }
- else
- {
- vip = host_create_any(AF_INET6);
- }
- }
- else
- {
- if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':'))
- {
- vip = host_create_any(AF_INET6);
- }
- else
- {
- vip = host_create_any(AF_INET);
- }
- }
- }
- }
switch (msg->add_conn.unique)
{
case 1: /* yes */
@@ -778,10 +708,126 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
msg->add_conn.mobike, msg->add_conn.aggressive,
msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout,
- vip, msg->add_conn.other.sourceip_mask ?
- msg->add_conn.name : msg->add_conn.other.sourceip,
msg->add_conn.ikeme.mediation, mediated_by, peer_id);
+ if (msg->add_conn.other.sourceip)
+ {
+ enumerator_t *enumerator;
+ char *token;
+
+ enumerator = enumerator_create_token(msg->add_conn.other.sourceip,
+ ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
+ streq(token, "%config") || streq(token, "%cfg") ||
+ streq(token, "%config4") || streq(token, "%config6"))
+ {
+ /* empty pool, uses connection name */
+ this->attributes->add_pool(this->attributes,
+ mem_pool_create(msg->add_conn.name, NULL, 0));
+ peer_cfg->add_pool(peer_cfg, msg->add_conn.name);
+ }
+ else if (*token == '%')
+ {
+ /* external named pool */
+ peer_cfg->add_pool(peer_cfg, token + 1);
+ }
+ else
+ {
+ /* in-memory pool, named using CIDR notation */
+ host_t *base;
+ int bits;
+
+ base = host_create_from_subnet(token, &bits);
+ if (base)
+ {
+ this->attributes->add_pool(this->attributes,
+ mem_pool_create(token, base, bits));
+ peer_cfg->add_pool(peer_cfg, token);
+ base->destroy(base);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "IP pool %s invalid, ignored", token);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+
+ if (msg->add_conn.me.sourceip)
+ {
+ enumerator_t *enumerator;
+ char *token;
+
+ enumerator = enumerator_create_token(msg->add_conn.me.sourceip, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ host_t *vip = NULL;
+
+ if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
+ streq(token, "%config") || streq(token, "%cfg"))
+ { /* try to deduce an address family */
+ if (msg->add_conn.me.subnets)
+ { /* use the same family as in local subnet, if any */
+ if (strchr(msg->add_conn.me.subnets, '.'))
+ {
+ vip = host_create_any(AF_INET);
+ }
+ else
+ {
+ vip = host_create_any(AF_INET6);
+ }
+ }
+ else if (msg->add_conn.other.subnets)
+ { /* use the same family as in remote subnet, if any */
+ if (strchr(msg->add_conn.other.subnets, '.'))
+ {
+ vip = host_create_any(AF_INET);
+ }
+ else
+ {
+ vip = host_create_any(AF_INET6);
+ }
+ }
+ else
+ {
+ if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':'))
+ {
+ vip = host_create_any(AF_INET6);
+ }
+ else
+ {
+ vip = host_create_any(AF_INET);
+ }
+ }
+ }
+ else if (streq(token, "%config4"))
+ {
+ vip = host_create_any(AF_INET);
+ }
+ else if (streq(token, "%config6"))
+ {
+ vip = host_create_any(AF_INET6);
+ }
+ else
+ {
+ vip = host_create_from_string(token, 0);
+ if (vip)
+ {
+ DBG1(DBG_CFG, "ignored invalid subnet token: %s", token);
+ }
+ }
+
+ if (vip)
+ {
+ peer_cfg->add_virtual_ip(peer_cfg, vip);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+
/* build leftauth= */
auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
if (auth_cfg)
@@ -1240,7 +1286,8 @@ METHOD(stroke_config_t, destroy, void,
/*
* see header file
*/
-stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
+stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
+ stroke_attribute_t *attributes)
{
private_stroke_config_t *this;
@@ -1260,6 +1307,7 @@ stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
.mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
.ca = ca,
.cred = cred,
+ .attributes = attributes,
);
return &this->public;
diff --git a/src/libcharon/plugins/stroke/stroke_config.h b/src/libcharon/plugins/stroke/stroke_config.h
index 450d517f3..894e03ce4 100644
--- a/src/libcharon/plugins/stroke/stroke_config.h
+++ b/src/libcharon/plugins/stroke/stroke_config.h
@@ -26,6 +26,7 @@
#include <stroke_msg.h>
#include "stroke_ca.h"
#include "stroke_cred.h"
+#include "stroke_attribute.h"
typedef struct stroke_config_t stroke_config_t;
@@ -71,6 +72,7 @@ struct stroke_config_t {
/**
* Create a stroke_config instance.
*/
-stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred);
+stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
+ stroke_attribute_t *attributes);
#endif /** STROKE_CONFIG_H_ @}*/
diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c
index 163a2a750..233d4088f 100644
--- a/src/libcharon/plugins/stroke/stroke_control.c
+++ b/src/libcharon/plugins/stroke/stroke_control.c
@@ -407,10 +407,10 @@ METHOD(stroke_control_t, rekey, void,
METHOD(stroke_control_t, terminate_srcip, void,
private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
{
- enumerator_t *enumerator;
+ enumerator_t *enumerator, *vips;
ike_sa_t *ike_sa;
host_t *start = NULL, *end = NULL, *vip;
- chunk_t chunk_start, chunk_end = chunk_empty, chunk_vip;
+ chunk_t chunk_start, chunk_end = chunk_empty, chunk;
if (msg->terminate_srcip.start)
{
@@ -438,33 +438,40 @@ METHOD(stroke_control_t, terminate_srcip, void,
charon->controller, TRUE);
while (enumerator->enumerate(enumerator, &ike_sa))
{
- vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (!vip)
- {
- continue;
- }
- if (!end)
+ bool match = FALSE;
+
+ vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
+ while (vips->enumerate(vips, &vip))
{
- if (!vip->ip_equals(vip, start))
+ if (!end)
{
- continue;
+ if (vip->ip_equals(vip, start))
+ {
+ match = TRUE;
+ break;
+ }
}
- }
- else
- {
- chunk_vip = vip->get_address(vip);
- if (chunk_vip.len != chunk_start.len ||
- chunk_vip.len != chunk_end.len ||
- memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 ||
- memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0)
+ else
{
- continue;
+ chunk = vip->get_address(vip);
+ if (chunk.len == chunk_start.len &&
+ chunk.len == chunk_end.len &&
+ memcmp(chunk.ptr, chunk_start.ptr, chunk.len) >= 0 &&
+ memcmp(chunk.ptr, chunk_end.ptr, chunk.len) <= 0)
+ {
+ match = TRUE;
+ break;
+ }
}
}
+ vips->destroy(vips);
- /* schedule delete asynchronously */
- lib->processor->queue_job(lib->processor, (job_t*)
+ if (match)
+ {
+ /* schedule delete asynchronously */
+ lib->processor->queue_job(lib->processor, (job_t*)
delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
+ }
}
enumerator->destroy(enumerator);
start->destroy(start);
diff --git a/src/libcharon/plugins/stroke/stroke_handler.c b/src/libcharon/plugins/stroke/stroke_handler.c
new file mode 100644
index 000000000..523151efb
--- /dev/null
+++ b/src/libcharon/plugins/stroke/stroke_handler.c
@@ -0,0 +1,231 @@
+/*
+ * 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 "stroke_handler.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <threading/rwlock.h>
+
+typedef struct private_stroke_handler_t private_stroke_handler_t;
+
+/**
+ * Private data of an stroke_handler_t object.
+ */
+struct private_stroke_handler_t {
+
+ /**
+ * Public stroke_handler_t interface.
+ */
+ stroke_handler_t public;
+
+ /**
+ * List of connection specific attributes, as attributes_t
+ */
+ linked_list_t *attrs;
+
+ /**
+ * rwlock to lock access to pools
+ */
+ rwlock_t *lock;
+};
+
+/**
+ * Attributes assigned to a connection
+ */
+typedef struct {
+ /** name of the connection */
+ char *name;
+ /** list of DNS attributes, as host_t */
+ linked_list_t *dns;
+} attributes_t;
+
+/**
+ * Destroy an attributes_t entry
+ */
+static void attributes_destroy(attributes_t *this)
+{
+ this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Filter function to convert host to DNS configuration attributes
+ */
+static bool attr_filter(void *lock, host_t **in,
+ configuration_attribute_type_t *type,
+ void *dummy, chunk_t *data)
+{
+ host_t *host = *in;
+
+ switch (host->get_family(host))
+ {
+ case AF_INET:
+ *type = INTERNAL_IP4_DNS;
+ break;
+ case AF_INET6:
+ *type = INTERNAL_IP6_DNS;
+ break;
+ default:
+ return FALSE;
+ }
+ if (host->is_anyaddr(host))
+ {
+ *data = chunk_empty;
+ }
+ else
+ {
+ *data = host->get_address(host);
+ }
+ return TRUE;
+}
+
+METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
+ private_stroke_handler_t *this, identification_t *server,
+ linked_list_t *vips)
+{
+ ike_sa_t *ike_sa;
+ peer_cfg_t *peer_cfg;
+ enumerator_t *enumerator;
+ attributes_t *attr;
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa)
+ {
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ this->lock->read_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
+ {
+ enumerator->destroy(enumerator);
+ return enumerator_create_filter(
+ attr->dns->create_enumerator(attr->dns),
+ (void*)attr_filter, this->lock,
+ (void*)this->lock->unlock);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ }
+ return enumerator_create_empty();
+}
+
+METHOD(stroke_handler_t, add_attributes, void,
+ private_stroke_handler_t *this, stroke_msg_t *msg)
+{
+ if (msg->add_conn.me.dns)
+ {
+ enumerator_t *enumerator;
+ attributes_t *attr = NULL;
+ host_t *host;
+ char *token;
+
+ enumerator = enumerator_create_token(msg->add_conn.me.dns, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ if (streq(token, "%config") || streq(token, "%config4"))
+ {
+ host = host_create_any(AF_INET);
+ }
+ else if (streq(token, "%config6"))
+ {
+ host = host_create_any(AF_INET6);
+ }
+ else
+ {
+ host = host_create_from_string(token, 0);
+ }
+ if (host)
+ {
+ if (!attr)
+ {
+ INIT(attr,
+ .name = strdup(msg->add_conn.name),
+ .dns = linked_list_create(),
+ );
+ }
+ attr->dns->insert_last(attr->dns, host);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (attr)
+ {
+ this->lock->write_lock(this->lock);
+ this->attrs->insert_last(this->attrs, attr);
+ this->lock->unlock(this->lock);
+ }
+ }
+}
+
+METHOD(stroke_handler_t, del_attributes, void,
+ private_stroke_handler_t *this, stroke_msg_t *msg)
+{
+ enumerator_t *enumerator;
+ attributes_t *attr;
+
+ this->lock->write_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (streq(msg->del_conn.name, attr->name))
+ {
+ this->attrs->remove_at(this->attrs, enumerator);
+ attributes_destroy(attr);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(stroke_handler_t, destroy, void,
+ private_stroke_handler_t *this)
+{
+ this->lock->destroy(this->lock);
+ this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
+ free(this);
+}
+
+/**
+ * See header
+ */
+stroke_handler_t *stroke_handler_create()
+{
+ private_stroke_handler_t *this;
+
+ INIT(this,
+ .public = {
+ .handler = {
+ .handle = (void*)return_false,
+ .release = (void*)return_false,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ },
+ .add_attributes = _add_attributes,
+ .del_attributes = _del_attributes,
+ .destroy = _destroy,
+ },
+ .attrs = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/stroke/stroke_handler.h b/src/libcharon/plugins/stroke/stroke_handler.h
new file mode 100644
index 000000000..ab76f80b0
--- /dev/null
+++ b/src/libcharon/plugins/stroke/stroke_handler.h
@@ -0,0 +1,64 @@
+/*
+ * 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 stroke_handler stroke_handler
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_HANDLER_H_
+#define STROKE_HANDLER_H_
+
+#include <stroke_msg.h>
+#include <attributes/attribute_handler.h>
+
+typedef struct stroke_handler_t stroke_handler_t;
+
+/**
+ * Handler requesting DNS attributes as defined with leftdns option.
+ */
+struct stroke_handler_t {
+
+ /**
+ * Implements the attribute_handler_t interface
+ */
+ attribute_handler_t handler;
+
+ /**
+ * Add connection specific configuration attributes.
+ *
+ * @param msg stroke message
+ */
+ void (*add_attributes)(stroke_handler_t *this, stroke_msg_t *msg);
+
+ /**
+ * Remove connection specific configuration attributes.
+ *
+ * @param msg stroke message
+ */
+ void (*del_attributes)(stroke_handler_t *this, stroke_msg_t *msg);
+
+ /**
+ * Destroy a stroke_handler_t.
+ */
+ void (*destroy)(stroke_handler_t *this);
+};
+
+/**
+ * Create a stroke_handler instance.
+ */
+stroke_handler_t *stroke_handler_create();
+
+#endif /** STROKE_HANDLER_H_ @}*/
diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c
index 6bf65cc7e..241f0fbf6 100644
--- a/src/libcharon/plugins/stroke/stroke_socket.c
+++ b/src/libcharon/plugins/stroke/stroke_socket.c
@@ -37,6 +37,7 @@
#include "stroke_cred.h"
#include "stroke_ca.h"
#include "stroke_attribute.h"
+#include "stroke_handler.h"
#include "stroke_list.h"
/**
@@ -99,6 +100,11 @@ struct private_stroke_socket_t {
stroke_attribute_t *attribute;
/**
+ * attribute handler (requests only)
+ */
+ stroke_handler_t *handler;
+
+ /**
* controller to control daemon
*/
stroke_control_t *control;
@@ -171,6 +177,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
pop_string(msg, &end->address);
pop_string(msg, &end->subnets);
pop_string(msg, &end->sourceip);
+ pop_string(msg, &end->dns);
pop_string(msg, &end->auth);
pop_string(msg, &end->auth2);
pop_string(msg, &end->id);
@@ -188,6 +195,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
DBG2(DBG_CFG, " %s=%s", label, end->address);
DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets);
DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip);
+ DBG2(DBG_CFG, " %sdns=%s", label, end->dns);
DBG2(DBG_CFG, " %sauth=%s", label, end->auth);
DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2);
DBG2(DBG_CFG, " %sid=%s", label, end->id);
@@ -235,7 +243,8 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
DBG2(DBG_CFG, " keyexchange=ikev%u", msg->add_conn.version);
this->config->add(this->config, msg);
- this->attribute->add_pool(this->attribute, msg);
+ this->attribute->add_dns(this->attribute, msg);
+ this->handler->add_attributes(this->handler, msg);
}
/**
@@ -247,7 +256,8 @@ static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
this->config->del(this->config, msg);
- this->attribute->del_pool(this->attribute, msg);
+ this->attribute->del_dns(this->attribute, msg);
+ this->handler->del_attributes(this->handler, msg);
}
/**
@@ -787,10 +797,12 @@ METHOD(stroke_socket_t, destroy, void,
lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
charon->backends->remove_backend(charon->backends, &this->config->backend);
hydra->attributes->remove_provider(hydra->attributes, &this->attribute->provider);
+ hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler);
this->cred->destroy(this->cred);
this->ca->destroy(this->ca);
this->config->destroy(this->config);
this->attribute->destroy(this->attribute);
+ this->handler->destroy(this->handler);
this->control->destroy(this->control);
this->list->destroy(this->list);
free(this);
@@ -817,8 +829,9 @@ stroke_socket_t *stroke_socket_create()
this->cred = stroke_cred_create();
this->attribute = stroke_attribute_create();
+ this->handler = stroke_handler_create();
this->ca = stroke_ca_create(this->cred);
- this->config = stroke_config_create(this->ca, this->cred);
+ this->config = stroke_config_create(this->ca, this->cred, this->attribute);
this->control = stroke_control_create();
this->list = stroke_list_create(this->attribute);
@@ -833,6 +846,7 @@ stroke_socket_t *stroke_socket_create()
lib->credmgr->add_set(lib->credmgr, &this->cred->set);
charon->backends->add_backend(charon->backends, &this->config->backend);
hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider);
+ hydra->attributes->add_handler(hydra->attributes, &this->handler->handler);
lib->processor->queue_job(lib->processor,
(job_t*)callback_job_create_with_prio((callback_job_cb_t)receive, this,
diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c
index 5b698b8b2..1201f568e 100644
--- a/src/libcharon/plugins/uci/uci_config.c
+++ b/src/libcharon/plugins/uci/uci_config.c
@@ -178,7 +178,6 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool,
1800, 900, /* jitter, overtime */
TRUE, FALSE, /* mobike, aggressive */
60, 0, /* DPD delay, timeout */
- NULL, NULL, /* vip, pool */
FALSE, NULL, NULL); /* mediation, med by, peer id */
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
diff --git a/src/libcharon/plugins/updown/Makefile.am b/src/libcharon/plugins/updown/Makefile.am
index 312c8d7e8..30683d83e 100644
--- a/src/libcharon/plugins/updown/Makefile.am
+++ b/src/libcharon/plugins/updown/Makefile.am
@@ -12,6 +12,7 @@ endif
libstrongswan_updown_la_SOURCES = \
updown_plugin.h updown_plugin.c \
+ updown_handler.h updown_handler.c \
updown_listener.h updown_listener.c
libstrongswan_updown_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/updown/updown_handler.c b/src/libcharon/plugins/updown/updown_handler.c
new file mode 100644
index 000000000..b2ac02e85
--- /dev/null
+++ b/src/libcharon/plugins/updown/updown_handler.c
@@ -0,0 +1,243 @@
+/*
+ * 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 "updown_handler.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <threading/rwlock.h>
+
+typedef struct private_updown_handler_t private_updown_handler_t;
+
+/**
+ * Private data of an updown_handler_t object.
+ */
+struct private_updown_handler_t {
+
+ /**
+ * Public updown_handler_t interface.
+ */
+ updown_handler_t public;
+
+ /**
+ * List of connection specific attributes, as attributes_t
+ */
+ linked_list_t *attrs;
+
+ /**
+ * rwlock to lock access to pools
+ */
+ rwlock_t *lock;
+};
+
+/**
+ * Attributes assigned to an IKE_SA
+ */
+typedef struct {
+ /** unique IKE_SA identifier */
+ u_int id;
+ /** list of DNS attributes, as host_t */
+ linked_list_t *dns;
+} attributes_t;
+
+/**
+ * Destroy an attributes_t entry
+ */
+static void attributes_destroy(attributes_t *this)
+{
+ this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+ free(this);
+}
+
+METHOD(attribute_handler_t, handle, bool,
+ private_updown_handler_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ attributes_t *current, *attr = NULL;
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ host_t *host;
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (!ike_sa)
+ {
+ return FALSE;
+ }
+ switch (type)
+ {
+ case INTERNAL_IP4_DNS:
+ host = host_create_from_chunk(AF_INET, data, 0);
+ break;
+ case INTERNAL_IP6_DNS:
+ host = host_create_from_chunk(AF_INET6, data, 0);
+ break;
+ default:
+ return FALSE;
+ }
+ if (!host)
+ {
+ return FALSE;
+ }
+
+ this->lock->write_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ if (current->id == ike_sa->get_unique_id(ike_sa))
+ {
+ attr = current;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!attr)
+ {
+ INIT(attr,
+ .id = ike_sa->get_unique_id(ike_sa),
+ .dns = linked_list_create(),
+ );
+ this->attrs->insert_last(this->attrs, attr);
+ }
+ attr->dns->insert_last(attr->dns, host);
+ this->lock->unlock(this->lock);
+
+ return TRUE;
+}
+
+METHOD(attribute_handler_t, release, void,
+ private_updown_handler_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ attributes_t *attr;
+ enumerator_t *enumerator, *servers;
+ ike_sa_t *ike_sa;
+ host_t *host;
+ bool found = FALSE;
+ int family;
+
+ switch (type)
+ {
+ case INTERNAL_IP4_DNS:
+ family = AF_INET;
+ break;
+ case INTERNAL_IP6_DNS:
+ family = AF_INET6;
+ break;
+ default:
+ return;
+ }
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa)
+ {
+ this->lock->write_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (attr->id == ike_sa->get_unique_id(ike_sa))
+ {
+ servers = attr->dns->create_enumerator(attr->dns);
+ while (servers->enumerate(servers, &host))
+ {
+ if (host->get_family(host) == family &&
+ chunk_equals(data, host->get_address(host)))
+ {
+ attr->dns->remove_at(attr->dns, servers);
+ host->destroy(host);
+ found = TRUE;
+ break;
+ }
+ }
+ servers->destroy(servers);
+ if (attr->dns->get_count(attr->dns) == 0)
+ {
+ this->attrs->remove_at(this->attrs, enumerator);
+ attributes_destroy(attr);
+ break;
+ }
+ }
+ if (found)
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ }
+}
+
+METHOD(updown_handler_t, create_dns_enumerator, enumerator_t*,
+ private_updown_handler_t *this, u_int id)
+{
+ attributes_t *attr;
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (!ike_sa)
+ {
+ return FALSE;
+ }
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->attrs->create_enumerator(this->attrs);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (attr->id == ike_sa->get_unique_id(ike_sa))
+ {
+ enumerator->destroy(enumerator);
+ return enumerator_create_cleaner(
+ attr->dns->create_enumerator(attr->dns),
+ (void*)this->lock->unlock, this->lock);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ return enumerator_create_empty();
+}
+
+
+METHOD(updown_handler_t, destroy, void,
+ private_updown_handler_t *this)
+{
+ this->lock->destroy(this->lock);
+ this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
+ free(this);
+}
+
+/**
+ * See header
+ */
+updown_handler_t *updown_handler_create()
+{
+ private_updown_handler_t *this;
+
+ INIT(this,
+ .public = {
+ .handler = {
+ .handle = _handle,
+ .release = _release,
+ .create_attribute_enumerator = enumerator_create_empty,
+ },
+ .create_dns_enumerator = _create_dns_enumerator,
+ .destroy = _destroy,
+ },
+ .attrs = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/updown/updown_handler.h b/src/libcharon/plugins/updown/updown_handler.h
new file mode 100644
index 000000000..d4de880b8
--- /dev/null
+++ b/src/libcharon/plugins/updown/updown_handler.h
@@ -0,0 +1,57 @@
+/*
+ * 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 updown_handler updown_handler
+ * @{ @ingroup updown
+ */
+
+#ifndef UPDOWN_HANDLER_H_
+#define UPDOWN_HANDLER_H_
+
+#include <attributes/attribute_handler.h>
+
+typedef struct updown_handler_t updown_handler_t;
+
+/**
+ * Handler storing configuration attributes to pass to updown script.
+ */
+struct updown_handler_t {
+
+ /**
+ * Implements the attribute_handler_t interface
+ */
+ attribute_handler_t handler;
+
+ /**
+ * Create an enumerator over received DNS servers.
+ *
+ * @param id unique IKE_SA identifier to get attributes for
+ * @return enumerator over host_t*
+ */
+ enumerator_t* (*create_dns_enumerator)(updown_handler_t *this, u_int id);
+
+ /**
+ * Destroy a updown_handler_t.
+ */
+ void (*destroy)(updown_handler_t *this);
+};
+
+/**
+ * Create a updown_handler instance.
+ */
+updown_handler_t *updown_handler_create();
+
+#endif /** UPDOWN_HANDLER_H_ @}*/
diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c
index 2bd757ec7..2f9f2ef91 100644
--- a/src/libcharon/plugins/updown/updown_listener.c
+++ b/src/libcharon/plugins/updown/updown_listener.c
@@ -38,6 +38,11 @@ struct private_updown_listener_t {
* List of cached interface names
*/
linked_list_t *iface_cache;
+
+ /**
+ * DNS attribute handler
+ */
+ updown_handler_t *handler;
};
typedef struct cache_entry_t cache_entry_t;
@@ -90,6 +95,85 @@ static char* uncache_iface(private_updown_listener_t *this, u_int32_t reqid)
return iface;
}
+/**
+ * Create variables for handled DNS attributes
+ */
+static char *make_dns_vars(private_updown_listener_t *this, ike_sa_t *ike_sa)
+{
+ enumerator_t *enumerator;
+ host_t *host;
+ int v4 = 0, v6 = 0;
+ char total[512] = "", current[64];
+
+ if (!this->handler)
+ {
+ return strdup("");
+ }
+
+ enumerator = this->handler->create_dns_enumerator(this->handler,
+ ike_sa->get_unique_id(ike_sa));
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ switch (host->get_family(host))
+ {
+ case AF_INET:
+ snprintf(current, sizeof(current),
+ "PLUTO_DNS4_%d='%H' ", ++v4, host);
+ break;
+ case AF_INET6:
+ snprintf(current, sizeof(current),
+ "PLUTO_DNS6_%d='%H' ", ++v6, host);
+ break;
+ default:
+ continue;
+ }
+ strncat(total, current, sizeof(total) - strlen(total) - 1);
+ }
+ enumerator->destroy(enumerator);
+
+ return strdup(total);
+}
+
+/**
+ * Create variables for local virtual IPs
+ */
+static char *make_vip_vars(private_updown_listener_t *this, ike_sa_t *ike_sa)
+{
+ enumerator_t *enumerator;
+ host_t *host;
+ int v4 = 0, v6 = 0;
+ char total[512] = "", current[64];
+ bool first = TRUE;
+
+ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ if (first)
+ { /* legacy variable for first VIP */
+ snprintf(current, sizeof(current),
+ "PLUTO_MY_SOURCEIP='%H' ", host);
+ strncat(total, current, sizeof(total) - strlen(total) - 1);
+ }
+ switch (host->get_family(host))
+ {
+ case AF_INET:
+ snprintf(current, sizeof(current),
+ "PLUTO_MY_SOURCEIP4_%d='%H' ", ++v4, host);
+ break;
+ case AF_INET6:
+ snprintf(current, sizeof(current),
+ "PLUTO_MY_SOURCEIP6_%d='%H' ", ++v6, host);
+ break;
+ default:
+ continue;
+ }
+ strncat(total, current, sizeof(total) - strlen(total) - 1);
+ }
+ enumerator->destroy(enumerator);
+
+ return strdup(total);
+}
+
METHOD(listener_t, child_updown, bool,
private_updown_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
bool up)
@@ -97,11 +181,10 @@ METHOD(listener_t, child_updown, bool,
traffic_selector_t *my_ts, *other_ts;
enumerator_t *enumerator;
child_cfg_t *config;
- host_t *vip, *me, *other;
+ host_t *me, *other;
char *script;
config = child_sa->get_config(child_sa);
- vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
script = config->get_updown(config);
me = ike_sa->get_my_host(ike_sa);
other = ike_sa->get_other_host(ike_sa);
@@ -117,7 +200,7 @@ METHOD(listener_t, child_updown, bool,
char command[1024];
host_t *my_client, *other_client;
u_int8_t my_client_mask, other_client_mask;
- char *virtual_ip, *iface, *mark_in, *mark_out, *udp_enc;
+ char *virtual_ip, *iface, *mark_in, *mark_out, *udp_enc, *dns;
mark_t mark;
bool is_host, is_ipv6;
FILE *shell;
@@ -125,20 +208,7 @@ METHOD(listener_t, child_updown, bool,
my_ts->to_subnet(my_ts, &my_client, &my_client_mask);
other_ts->to_subnet(other_ts, &other_client, &other_client_mask);
- if (vip)
- {
- if (asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", vip) < 0)
- {
- virtual_ip = NULL;
- }
- }
- else
- {
- if (asprintf(&virtual_ip, "") < 0)
- {
- virtual_ip = NULL;
- }
- }
+ virtual_ip = make_vip_vars(this, ike_sa);
/* check for the presence of an inbound mark */
mark = config->get_mark(config, TRUE);
@@ -209,6 +279,8 @@ METHOD(listener_t, child_updown, bool,
iface = uncache_iface(this, child_sa->get_reqid(child_sa));
}
+ dns = make_dns_vars(this, ike_sa);
+
/* determine IPv4/IPv6 and client/host situation */
is_host = my_ts->is_host(my_ts, me);
is_ipv6 = is_host ? (me->get_family(me) == AF_INET6) :
@@ -239,6 +311,7 @@ METHOD(listener_t, child_updown, bool,
"%s"
"%s"
"%s"
+ "%s"
"%s",
up ? "up" : "down",
is_host ? "-host" : "-client",
@@ -259,6 +332,7 @@ METHOD(listener_t, child_updown, bool,
mark_out,
udp_enc,
config->get_hostaccess(config) ? "PLUTO_HOST_ACCESS='1' " : "",
+ dns,
script);
my_client->destroy(my_client);
other_client->destroy(other_client);
@@ -266,6 +340,7 @@ METHOD(listener_t, child_updown, bool,
free(mark_in);
free(mark_out);
free(udp_enc);
+ free(dns);
free(iface);
DBG3(DBG_CHD, "running updown script: %s", command);
@@ -315,7 +390,7 @@ METHOD(updown_listener_t, destroy, void,
/**
* See header
*/
-updown_listener_t *updown_listener_create()
+updown_listener_t *updown_listener_create(updown_handler_t *handler)
{
private_updown_listener_t *this;
@@ -327,6 +402,7 @@ updown_listener_t *updown_listener_create()
.destroy = _destroy,
},
.iface_cache = linked_list_create(),
+ .handler = handler,
);
return &this->public;
diff --git a/src/libcharon/plugins/updown/updown_listener.h b/src/libcharon/plugins/updown/updown_listener.h
index 5b866c4e5..2d9b56ade 100644
--- a/src/libcharon/plugins/updown/updown_listener.h
+++ b/src/libcharon/plugins/updown/updown_listener.h
@@ -23,6 +23,8 @@
#include <bus/bus.h>
+#include "updown_handler.h"
+
typedef struct updown_listener_t updown_listener_t;
/**
@@ -44,6 +46,6 @@ struct updown_listener_t {
/**
* Create a updown_listener instance.
*/
-updown_listener_t *updown_listener_create();
+updown_listener_t *updown_listener_create(updown_handler_t *handler);
#endif /** UPDOWN_LISTENER_H_ @}*/
diff --git a/src/libcharon/plugins/updown/updown_plugin.c b/src/libcharon/plugins/updown/updown_plugin.c
index 2ce2d3257..e1f0d1380 100644
--- a/src/libcharon/plugins/updown/updown_plugin.c
+++ b/src/libcharon/plugins/updown/updown_plugin.c
@@ -15,8 +15,10 @@
#include "updown_plugin.h"
#include "updown_listener.h"
+#include "updown_handler.h"
#include <daemon.h>
+#include <hydra.h>
typedef struct private_updown_plugin_t private_updown_plugin_t;
@@ -34,6 +36,11 @@ struct private_updown_plugin_t {
* Listener interface, listens to CHILD_SA state changes
*/
updown_listener_t *listener;
+
+ /**
+ * Attribute handler, to pass DNS servers to updown
+ */
+ updown_handler_t *handler;
};
METHOD(plugin_t, get_name, char*,
@@ -47,6 +54,12 @@ METHOD(plugin_t, destroy, void,
{
charon->bus->remove_listener(charon->bus, &this->listener->listener);
this->listener->destroy(this->listener);
+ if (this->handler)
+ {
+ hydra->attributes->remove_handler(hydra->attributes,
+ &this->handler->handler);
+ this->handler->destroy(this->handler);
+ }
free(this);
}
@@ -65,9 +78,16 @@ plugin_t *updown_plugin_create()
.destroy = _destroy,
},
},
- .listener = updown_listener_create(),
);
+ if (lib->settings->get_bool(lib->settings,
+ "charon.plugins.updown.dns_handler", FALSE))
+ {
+ this->handler = updown_handler_create();
+ hydra->attributes->add_handler(hydra->attributes,
+ &this->handler->handler);
+ }
+ this->listener = updown_listener_create(this->handler);
charon->bus->add_listener(charon->bus, &this->listener->listener);
return &this->public.plugin;
diff --git a/src/libcharon/processing/jobs/migrate_job.c b/src/libcharon/processing/jobs/migrate_job.c
index 57f344980..2ebfc6714 100644
--- a/src/libcharon/processing/jobs/migrate_job.c
+++ b/src/libcharon/processing/jobs/migrate_job.c
@@ -79,9 +79,10 @@ METHOD(job_t, execute, job_requeue_t,
}
if (ike_sa)
{
- enumerator_t *children;
+ enumerator_t *children, *enumerator;
child_sa_t *child_sa;
host_t *host;
+ linked_list_t *vips;
children = ike_sa->create_child_sa_enumerator(ike_sa);
while (children->enumerate(children, (void**)&child_sa))
@@ -104,14 +105,22 @@ METHOD(job_t, execute, job_requeue_t,
host->set_port(host, IKEV2_UDP_PORT);
ike_sa->set_other_host(ike_sa, host);
- if (child_sa->update(child_sa, this->local, this->remote,
- ike_sa->get_virtual_ip(ike_sa, TRUE),
+ vips = linked_list_create();
+ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ vips->insert_last(vips, host);
+ }
+ enumerator->destroy(enumerator);
+
+ if (child_sa->update(child_sa, this->local, this->remote, vips,
ike_sa->has_condition(ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED)
{
ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
child_sa->get_spi(child_sa, TRUE));
}
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ vips->destroy(vips);
}
else
{
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index d5adb2527..c3fbd8b53 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -819,9 +819,18 @@ METHOD(child_sa_t, add_policies, status_t,
return status;
}
+/**
+ * Callback to reinstall a virtual IP
+ */
+static void reinstall_vip(host_t *vip, host_t *me)
+{
+ hydra->kernel_interface->del_ip(hydra->kernel_interface, vip);
+ hydra->kernel_interface->add_ip(hydra->kernel_interface, vip, me);
+}
+
METHOD(child_sa_t, update, status_t,
- private_child_sa_t *this, host_t *me, host_t *other, host_t *vip,
- bool encap)
+ private_child_sa_t *this, host_t *me, host_t *other, linked_list_t *vips,
+ bool encap)
{
child_sa_state_t old;
bool transport_proxy_mode;
@@ -927,13 +936,7 @@ METHOD(child_sa_t, update, status_t,
/* we reinstall the virtual IP to handle interface roaming
* correctly */
- if (vip)
- {
- hydra->kernel_interface->del_ip(hydra->kernel_interface,
- vip);
- hydra->kernel_interface->add_ip(hydra->kernel_interface,
- vip, me);
- }
+ vips->invoke_function(vips, (void*)reinstall_vip, me);
/* reinstall updated policies */
install_policies_internal(this, me, other, my_ts, other_ts,
diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h
index 712a4765c..dae3f2c18 100644
--- a/src/libcharon/sa/child_sa.h
+++ b/src/libcharon/sa/child_sa.h
@@ -346,12 +346,12 @@ struct child_sa_t {
*
* @param me the new local host
* @param other the new remote host
- * @param vip virtual IP, if any
+ * @param vips list of local virtual IPs
* @param TRUE to use UDP encapsulation for NAT traversal
* @return SUCCESS or FAILED
*/
status_t (*update)(child_sa_t *this, host_t *me, host_t *other,
- host_t *vip, bool encap);
+ linked_list_t *vips, bool encap);
/**
* Destroys a child_sa.
*/
diff --git a/src/libcharon/sa/eap/eap_manager.c b/src/libcharon/sa/eap/eap_manager.c
index d38754e01..520c0ce56 100644
--- a/src/libcharon/sa/eap/eap_manager.c
+++ b/src/libcharon/sa/eap/eap_manager.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -104,6 +105,44 @@ METHOD(eap_manager_t, remove_method, void,
this->lock->unlock(this->lock);
}
+/**
+ * filter the registered methods
+ */
+static bool filter_methods(uintptr_t role, eap_entry_t **entry,
+ eap_type_t *type, void *in, u_int32_t *vendor)
+{
+ if ((*entry)->role != (eap_role_t)role)
+ {
+ return FALSE;
+ }
+ if ((*entry)->vendor == 0 &&
+ ((*entry)->type < 4 || (*entry)->type == EAP_EXPANDED ||
+ (*entry)->type > EAP_EXPERIMENTAL))
+ { /* filter invalid types */
+ return FALSE;
+ }
+ if (type)
+ {
+ *type = (*entry)->type;
+ }
+ if (vendor)
+ {
+ *vendor = (*entry)->vendor;
+ }
+ return TRUE;
+}
+
+METHOD(eap_manager_t, create_enumerator, enumerator_t*,
+ private_eap_manager_t *this, eap_role_t role)
+{
+ this->lock->read_lock(this->lock);
+ return enumerator_create_cleaner(
+ enumerator_create_filter(
+ this->methods->create_enumerator(this->methods),
+ (void*)filter_methods, (void*)(uintptr_t)role, NULL),
+ (void*)this->lock->unlock, this->lock);
+}
+
METHOD(eap_manager_t, create_instance, eap_method_t*,
private_eap_manager_t *this, eap_type_t type, u_int32_t vendor,
eap_role_t role, identification_t *server, identification_t *peer)
@@ -150,6 +189,7 @@ eap_manager_t *eap_manager_create()
.public = {
.add_method = _add_method,
.remove_method = _remove_method,
+ .create_enumerator = _create_enumerator,
.create_instance = _create_instance,
.destroy = _destroy,
},
diff --git a/src/libcharon/sa/eap/eap_manager.h b/src/libcharon/sa/eap/eap_manager.h
index 868eaef06..e318ef57a 100644
--- a/src/libcharon/sa/eap/eap_manager.h
+++ b/src/libcharon/sa/eap/eap_manager.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -54,6 +55,17 @@ struct eap_manager_t {
void (*remove_method)(eap_manager_t *this, eap_constructor_t constructor);
/**
+ * Enumerate the registered EAP authentication methods for the given role.
+ *
+ * @note Only authentication types are enumerated (e.g. EAP-Identity is not
+ * even though it is registered as method with this manager).
+ *
+ * @param role EAP role of methods to enumerate
+ * @return enumerator over (eap_type_t type, u_int32_t vendor)
+ */
+ enumerator_t* (*create_enumerator)(eap_manager_t *this, eap_role_t role);
+
+ /**
* Create a new EAP method instance.
*
* @param type type of the EAP method
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 1e3d00f02..7672accc4 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -182,14 +182,14 @@ struct private_ike_sa_t {
keymat_t *keymat;
/**
- * Virtual IP on local host, if any
+ * Virtual IPs on local host
*/
- host_t *my_virtual_ip;
+ linked_list_t *my_vips;
/**
- * Virtual IP on remote host, if any
+ * Virtual IPs on remote host
*/
- host_t *other_virtual_ip;
+ linked_list_t *other_vips;
/**
* List of configuration attributes (attribute_entry_t)
@@ -735,7 +735,7 @@ METHOD(ike_sa_t, get_keymat, keymat_t*,
return this->keymat;
}
-METHOD(ike_sa_t, set_virtual_ip, void,
+METHOD(ike_sa_t, add_virtual_ip, void,
private_ike_sa_t *this, bool local, host_t *ip)
{
if (local)
@@ -744,39 +744,27 @@ METHOD(ike_sa_t, set_virtual_ip, void,
if (hydra->kernel_interface->add_ip(hydra->kernel_interface, ip,
this->my_host) == SUCCESS)
{
- if (this->my_virtual_ip)
- {
- DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
- hydra->kernel_interface->del_ip(hydra->kernel_interface,
- this->my_virtual_ip);
- }
- DESTROY_IF(this->my_virtual_ip);
- this->my_virtual_ip = ip->clone(ip);
+ this->my_vips->insert_last(this->my_vips, ip->clone(ip));
}
else
{
DBG1(DBG_IKE, "installing virtual IP %H failed", ip);
- this->my_virtual_ip = NULL;
}
}
else
{
- DESTROY_IF(this->other_virtual_ip);
- this->other_virtual_ip = ip->clone(ip);
+ this->other_vips->insert_last(this->other_vips, ip->clone(ip));
}
}
-METHOD(ike_sa_t, get_virtual_ip, host_t*,
+METHOD(ike_sa_t, create_virtual_ip_enumerator, enumerator_t*,
private_ike_sa_t *this, bool local)
{
if (local)
{
- return this->my_virtual_ip;
- }
- else
- {
- return this->other_virtual_ip;
+ return this->my_vips->create_enumerator(this->my_vips);
}
+ return this->other_vips->create_enumerator(this->other_vips);
}
METHOD(ike_sa_t, add_peer_address, void,
@@ -909,7 +897,7 @@ METHOD(ike_sa_t, update_hosts, void,
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
if (child_sa->update(child_sa, this->my_host,
- this->other_host, this->my_virtual_ip,
+ this->other_host, this->my_vips,
has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED)
{
this->public.rekey_child_sa(&this->public,
@@ -1458,7 +1446,7 @@ METHOD(ike_sa_t, reauth, status_t,
if (!has_condition(this, COND_ORIGINAL_INITIATOR))
{
DBG1(DBG_IKE, "initiator did not reauthenticate as requested");
- if (this->other_virtual_ip != NULL ||
+ if (this->other_vips->get_count(this->other_vips) != 0 ||
has_condition(this, COND_XAUTH_AUTHENTICATED) ||
has_condition(this, COND_EAP_AUTHENTICATED)
#ifdef ME
@@ -1562,7 +1550,7 @@ METHOD(ike_sa_t, reestablish, status_t,
/* check if we are able to reestablish this IKE_SA */
if (!has_condition(this, COND_ORIGINAL_INITIATOR) &&
- (this->other_virtual_ip != NULL ||
+ (this->other_vips->get_count(this->other_vips) != 0 ||
has_condition(this, COND_EAP_AUTHENTICATED)
#ifdef ME
|| this->is_mediation_server
@@ -1585,11 +1573,12 @@ METHOD(ike_sa_t, reestablish, status_t,
host = this->my_host;
new->set_my_host(new, host->clone(host));
/* if we already have a virtual IP, we reuse it */
- host = this->my_virtual_ip;
- if (host)
+ enumerator = this->my_vips->create_enumerator(this->my_vips);
+ while (enumerator->enumerate(enumerator, &host))
{
- new->set_virtual_ip(new, TRUE, host);
+ new->add_virtual_ip(new, TRUE, host);
}
+ enumerator->destroy(enumerator);
#ifdef ME
if (this->peer_cfg->is_mediation(this->peer_cfg))
@@ -1732,7 +1721,7 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t,
* We send the notify in IKE_AUTH if not yet ESTABLISHED. */
send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 &&
!has_condition(this, COND_ORIGINAL_INITIATOR) &&
- (this->other_virtual_ip != NULL ||
+ (this->other_vips->get_count(this->other_vips) != 0 ||
has_condition(this, COND_EAP_AUTHENTICATED));
if (lifetime < diff)
@@ -1937,6 +1926,7 @@ METHOD(ike_sa_t, inherit, void,
attribute_entry_t *entry;
enumerator_t *enumerator;
auth_cfg_t *cfg;
+ host_t *vip;
/* apply hosts and ids */
this->my_host->destroy(this->my_host);
@@ -1948,16 +1938,15 @@ METHOD(ike_sa_t, inherit, void,
this->my_id = other->my_id->clone(other->my_id);
this->other_id = other->other_id->clone(other->other_id);
- /* apply virtual assigned IPs... */
- if (other->my_virtual_ip)
+ /* apply assigned virtual IPs... */
+ while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS)
{
- this->my_virtual_ip = other->my_virtual_ip;
- other->my_virtual_ip = NULL;
+ other->my_vips->insert_first(other->my_vips, vip);
}
- if (other->other_virtual_ip)
+ while (this->other_vips->remove_last(this->other_vips,
+ (void**)&vip) == SUCCESS)
{
- this->other_virtual_ip = other->other_virtual_ip;
- other->other_virtual_ip = NULL;
+ other->other_vips->insert_first(other->other_vips, vip);
}
/* authentication information */
@@ -2032,6 +2021,7 @@ METHOD(ike_sa_t, destroy, void,
private_ike_sa_t *this)
{
attribute_entry_t *entry;
+ host_t *vip;
charon->bus->set_sa(charon->bus, &this->public);
@@ -2056,22 +2046,34 @@ METHOD(ike_sa_t, destroy, void,
DESTROY_IF(this->keymat);
- if (this->my_virtual_ip)
+ while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS)
{
- hydra->kernel_interface->del_ip(hydra->kernel_interface,
- this->my_virtual_ip);
- this->my_virtual_ip->destroy(this->my_virtual_ip);
+ hydra->kernel_interface->del_ip(hydra->kernel_interface, vip);
+ vip->destroy(vip);
}
- if (this->other_virtual_ip)
+ this->my_vips->destroy(this->my_vips);
+ while (this->other_vips->remove_last(this->other_vips,
+ (void**)&vip) == SUCCESS)
{
- if (this->peer_cfg && this->peer_cfg->get_pool(this->peer_cfg))
+ if (this->peer_cfg)
{
- hydra->attributes->release_address(hydra->attributes,
- this->peer_cfg->get_pool(this->peer_cfg),
- this->other_virtual_ip, get_other_eap_id(this));
+ enumerator_t *enumerator;
+ char *pool;
+
+ enumerator = this->peer_cfg->create_pool_enumerator(this->peer_cfg);
+ while (enumerator->enumerate(enumerator, &pool))
+ {
+ if (hydra->attributes->release_address(hydra->attributes, pool,
+ vip, get_other_eap_id(this)))
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
}
- this->other_virtual_ip->destroy(this->other_virtual_ip);
+ vip->destroy(vip);
}
+ this->other_vips->destroy(this->other_vips);
this->peer_addresses->destroy_offset(this->peer_addresses,
offsetof(host_t, destroy));
#ifdef ME
@@ -2190,8 +2192,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.generate_message = _generate_message,
.reset = _reset,
.get_unique_id = _get_unique_id,
- .set_virtual_ip = _set_virtual_ip,
- .get_virtual_ip = _get_virtual_ip,
+ .add_virtual_ip = _add_virtual_ip,
+ .create_virtual_ip_enumerator = _create_virtual_ip_enumerator,
.add_configuration_attribute = _add_configuration_attribute,
.set_kmaddress = _set_kmaddress,
.create_task_enumerator = _create_task_enumerator,
@@ -2226,6 +2228,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.other_auths = linked_list_create(),
.unique_id = ++unique_id,
.peer_addresses = linked_list_create(),
+ .my_vips = linked_list_create(),
+ .other_vips = linked_list_create(),
.attributes = linked_list_create(),
.keepalive_interval = lib->settings->get_time(lib->settings,
"%s.keep_alive", KEEPALIVE_INTERVAL, charon->name),
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index de9e0ede4..d2a394b6c 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -931,7 +931,7 @@ struct ike_sa_t {
status_t (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime);
/**
- * Set the virtual IP to use for this IKE_SA and its children.
+ * Add a virtual IP to use for this IKE_SA and its children.
*
* The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
* lifetime as the IKE_SA.
@@ -939,15 +939,15 @@ struct ike_sa_t {
* @param local TRUE to set local address, FALSE for remote
* @param ip IP to set as virtual IP
*/
- void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip);
+ void (*add_virtual_ip) (ike_sa_t *this, bool local, host_t *ip);
/**
- * Get the virtual IP configured.
+ * Create an enumerator over virtual IPs.
*
* @param local TRUE to get local virtual IP, FALSE for remote
- * @return host_t *virtual IP
+ * @return enumerator over host_t*
*/
- host_t* (*get_virtual_ip) (ike_sa_t *this, bool local);
+ enumerator_t* (*create_virtual_ip_enumerator) (ike_sa_t *this, bool local);
/**
* Register a configuration attribute to the IKE_SA.
diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c
index e5a48ec49..4096141ec 100644
--- a/src/libcharon/sa/ikev1/phase1.c
+++ b/src/libcharon/sa/ikev1/phase1.c
@@ -609,6 +609,34 @@ METHOD(phase1_t, get_id, identification_t*,
return id;
}
+METHOD(phase1_t, has_virtual_ip, bool,
+ private_phase1_t *this, peer_cfg_t *peer_cfg)
+{
+ enumerator_t *enumerator;
+ bool found = FALSE;
+ host_t *host;
+
+ enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg);
+ found = enumerator->enumerate(enumerator, &host);
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+METHOD(phase1_t, has_pool, bool,
+ private_phase1_t *this, peer_cfg_t *peer_cfg)
+{
+ enumerator_t *enumerator;
+ bool found = FALSE;
+ char *pool;
+
+ enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
+ found = enumerator->enumerate(enumerator, &pool);
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
METHOD(phase1_t, save_sa_payload, bool,
private_phase1_t *this, message_t *message)
{
@@ -748,6 +776,8 @@ phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator)
.get_auth_method = _get_auth_method,
.get_id = _get_id,
.select_config = _select_config,
+ .has_virtual_ip = _has_virtual_ip,
+ .has_pool = _has_pool,
.verify_auth = _verify_auth,
.build_auth = _build_auth,
.save_sa_payload = _save_sa_payload,
diff --git a/src/libcharon/sa/ikev1/phase1.h b/src/libcharon/sa/ikev1/phase1.h
index f1e95d88c..eaf8908e7 100644
--- a/src/libcharon/sa/ikev1/phase1.h
+++ b/src/libcharon/sa/ikev1/phase1.h
@@ -109,6 +109,22 @@ struct phase1_t {
identification_t* (*get_id)(phase1_t *this, peer_cfg_t *peer_cfg, bool local);
/**
+ * Check if peer config has virtual IPs pool assigned.
+ *
+ * @param peer_cfg peer_config to check
+ * @return TRUE if peer config contains at least one pool
+ */
+ bool (*has_pool)(phase1_t *this, peer_cfg_t *peer_cfg);
+
+ /**
+ * Check if peer config has virtual IPs to request
+ *
+ * @param peer_cfg peer_config to check
+ * @return TRUE if peer config contains at least one virtual IP
+ */
+ bool (*has_virtual_ip)(phase1_t *this, peer_cfg_t *peer_cfg);
+
+ /**
* Extract and store SA payload bytes from encoded message.
*
* @param message message to extract SA payload bytes from
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 3c84b5114..ea836b76e 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -346,15 +346,30 @@ METHOD(task_manager_t, retransmit, status_t,
*/
static bool mode_config_expected(private_task_manager_t *this)
{
+ enumerator_t *enumerator;
peer_cfg_t *peer_cfg;
+ char *pool;
+ host_t *host;
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (peer_cfg && peer_cfg->get_pool(peer_cfg))
+ if (peer_cfg)
{
- if (!this->ike_sa->get_virtual_ip(this->ike_sa, FALSE))
- {
+ enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
+ if (!enumerator->enumerate(enumerator, &pool))
+ { /* no pool configured */
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
+ FALSE);
+ if (!enumerator->enumerate(enumerator, &host))
+ { /* have a pool, but no VIP assigned yet */
+ enumerator->destroy(enumerator);
return TRUE;
}
+ enumerator->destroy(enumerator);
}
return FALSE;
}
@@ -1309,11 +1324,12 @@ METHOD(task_manager_t, queue_ike_reauth, void,
new->set_other_host(new, host->clone(host));
host = this->ike_sa->get_my_host(this->ike_sa);
new->set_my_host(new, host->clone(host));
- host = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
- if (host)
+ enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE);
+ while (enumerator->enumerate(enumerator, &host))
{
- new->set_virtual_ip(new, TRUE, host);
+ new->add_virtual_ip(new, TRUE, host);
}
+ enumerator->destroy(enumerator);
enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
while (enumerator->enumerate(enumerator, &child_sa))
diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
index 38962fc60..954dea880 100644
--- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
@@ -320,7 +320,7 @@ METHOD(task_t, build_i, status_t,
}
break;
}
- if (this->peer_cfg->get_virtual_ip(this->peer_cfg))
+ if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
{
this->ike_sa->queue_task(this->ike_sa,
(task_t*)mode_config_create(this->ike_sa, TRUE));
@@ -497,8 +497,8 @@ METHOD(task_t, process_r, status_t,
this->ike_sa->get_id(this->ike_sa)));
break;
}
- if (this->peer_cfg->get_pool(this->peer_cfg) == NULL &&
- this->peer_cfg->get_virtual_ip(this->peer_cfg))
+ if (!this->ph1->has_pool(this->ph1, this->peer_cfg) &&
+ this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
{
this->ike_sa->queue_task(this->ike_sa,
(task_t*)mode_config_create(this->ike_sa, TRUE));
diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c
index 539286938..9ccf9abf5 100644
--- a/src/libcharon/sa/ikev1/tasks/main_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/main_mode.c
@@ -524,8 +524,8 @@ METHOD(task_t, build_r, status_t,
this->ike_sa->get_id(this->ike_sa)));
break;
}
- if (this->peer_cfg->get_pool(this->peer_cfg) == NULL &&
- this->peer_cfg->get_virtual_ip(this->peer_cfg))
+ if (!this->ph1->has_pool(this->ph1, this->peer_cfg) &&
+ this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
{
this->ike_sa->queue_task(this->ike_sa,
(task_t*)mode_config_create(this->ike_sa, TRUE));
@@ -658,7 +658,7 @@ METHOD(task_t, process_i, status_t,
}
break;
}
- if (this->peer_cfg->get_virtual_ip(this->peer_cfg))
+ if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
{
this->ike_sa->queue_task(this->ike_sa,
(task_t*)mode_config_create(this->ike_sa, TRUE));
diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.c b/src/libcharon/sa/ikev1/tasks/mode_config.c
index ab3a81386..ef1b35c17 100644
--- a/src/libcharon/sa/ikev1/tasks/mode_config.c
+++ b/src/libcharon/sa/ikev1/tasks/mode_config.c
@@ -42,9 +42,9 @@ struct private_mode_config_t {
bool initiator;
/**
- * virtual ip
+ * Received list of virtual IPs, host_t*
*/
- host_t *virtual_ip;
+ linked_list_t *vips;
/**
* list of attributes requested and its handler, entry_t
@@ -174,8 +174,7 @@ static void process_attribute(private_mode_config_t *this,
}
if (ip)
{
- DESTROY_IF(this->virtual_ip);
- this->virtual_ip = ip;
+ this->vips->insert_last(this->vips, ip);
}
break;
}
@@ -239,23 +238,44 @@ METHOD(task_t, build_i, status_t,
peer_cfg_t *config;
configuration_attribute_type_t type;
chunk_t data;
- host_t *vip;
+ linked_list_t *vips;
+ host_t *host;
+
+ vips = linked_list_create();
/* reuse virtual IP if we already have one */
- vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
- if (!vip)
+ enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ vips->insert_last(vips, host);
+ }
+ enumerator->destroy(enumerator);
+
+ if (vips->get_count(vips) == 0)
{
config = this->ike_sa->get_peer_cfg(this->ike_sa);
- vip = config->get_virtual_ip(config);
+ enumerator = config->create_virtual_ip_enumerator(config);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ vips->insert_last(vips, host);
+ }
+ enumerator->destroy(enumerator);
}
- if (vip)
+
+ if (vips->get_count(vips))
{
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST);
- cp->add_attribute(cp, build_vip(vip));
+ enumerator = vips->create_enumerator(vips);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ cp->add_attribute(cp, build_vip(host));
+ }
+ enumerator->destroy(enumerator);
}
- enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes,
- this->ike_sa->get_other_id(this->ike_sa), vip);
+ enumerator = hydra->attributes->create_initiator_enumerator(
+ hydra->attributes,
+ this->ike_sa->get_other_id(this->ike_sa), vips);
while (enumerator->enumerate(enumerator, &handler, &type, &data))
{
configuration_attribute_t *ca;
@@ -279,6 +299,8 @@ METHOD(task_t, build_i, status_t,
}
enumerator->destroy(enumerator);
+ vips->destroy(vips);
+
if (cp)
{
message->add_payload(message, (payload_t*)cp);
@@ -299,37 +321,64 @@ METHOD(task_t, build_r, status_t,
enumerator_t *enumerator;
configuration_attribute_type_t type;
chunk_t value;
- host_t *vip = NULL;
cp_payload_t *cp = NULL;
peer_cfg_t *config;
identification_t *id;
+ linked_list_t *vips, *pools;
+ host_t *requested;
id = this->ike_sa->get_other_eap_id(this->ike_sa);
-
config = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (this->virtual_ip)
+ vips = linked_list_create();
+ pools = linked_list_create();
+
+ enumerator = this->vips->create_enumerator(this->vips);
+ while (enumerator->enumerate(enumerator, &requested))
{
- DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
- if (config->get_pool(config))
- {
- vip = hydra->attributes->acquire_address(hydra->attributes,
- config->get_pool(config), id, this->virtual_ip);
- }
- cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
- if (vip)
+ enumerator_t *poolenum;
+ char *pool;
+ host_t *found = NULL;
+
+ /* query all pools until we get an address */
+ DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
+
+ poolenum = config->create_pool_enumerator(config);
+ while (poolenum->enumerate(poolenum, &pool))
{
- DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id);
- this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
- cp->add_attribute(cp, build_vip(vip));
+ found = hydra->attributes->acquire_address(hydra->attributes,
+ pool, id, requested);
+ if (!found)
+ {
+ continue;
+ }
+ DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
+ this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
+ if (!cp)
+ {
+ cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
+ }
+ cp->add_attribute(cp, build_vip(found));
+ /* use pool to request other attributes */
+ if (pools->find_first(pools, NULL, (void**)&pool) == NOT_FOUND)
+ {
+ pools->insert_last(pools, pool);
+ }
+ vips->insert_last(vips, found);
+ break;
}
- else
+ poolenum->destroy(poolenum);
+
+ if (!found)
{
- DBG1(DBG_IKE, "no virtual IP found, sending empty config payload");
+ DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
+ requested, id);
}
}
+ enumerator->destroy(enumerator);
+
/* query registered providers for additional attributes to include */
enumerator = hydra->attributes->create_responder_enumerator(
- hydra->attributes, config->get_pool(config), id, vip);
+ hydra->attributes, pools, id, vips);
while (enumerator->enumerate(enumerator, &type, &value))
{
if (!cp)
@@ -343,25 +392,35 @@ METHOD(task_t, build_r, status_t,
type, value));
}
enumerator->destroy(enumerator);
+ vips->destroy_offset(vips, offsetof(host_t, destroy));
+ vips->destroy(vips);
if (cp)
{
cp->set_identifier(cp, this->identifier);
message->add_payload(message, (payload_t*)cp);
}
- DESTROY_IF(vip);
return SUCCESS;
}
METHOD(task_t, process_i, status_t,
private_mode_config_t *this, message_t *message)
{
+ enumerator_t *enumerator;
+ host_t *host;
+
process_payloads(this, message);
- if (this->virtual_ip)
+ enumerator = this->vips->create_enumerator(this->vips);
+ while (enumerator->enumerate(enumerator, &host))
{
- this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
+ if (!host->is_anyaddr(host))
+ {
+ this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
+ }
}
+ enumerator->destroy(enumerator);
+
return SUCCESS;
}
@@ -374,10 +433,9 @@ METHOD(task_t, get_type, task_type_t,
METHOD(task_t, migrate, void,
private_mode_config_t *this, ike_sa_t *ike_sa)
{
- DESTROY_IF(this->virtual_ip);
-
this->ike_sa = ike_sa;
- this->virtual_ip = NULL;
+ this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
+ this->vips = linked_list_create();
this->requested->destroy_function(this->requested, free);
this->requested = linked_list_create();
}
@@ -385,7 +443,7 @@ METHOD(task_t, migrate, void,
METHOD(task_t, destroy, void,
private_mode_config_t *this)
{
- DESTROY_IF(this->virtual_ip);
+ this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
this->requested->destroy_function(this->requested, free);
free(this);
}
@@ -408,6 +466,7 @@ mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator)
.initiator = initiator,
.ike_sa = ike_sa,
.requested = linked_list_create(),
+ .vips = linked_list_create(),
);
if (initiator)
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 67d1b45f1..73a23f4ea 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -398,11 +398,12 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
linked_list_t *supplied)
{
traffic_selector_t *ts;
+ enumerator_t *enumerator;
linked_list_t *list;
host_t *host;
- host = this->ike_sa->get_virtual_ip(this->ike_sa, local);
- if (!host)
+ enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, local);
+ if (!enumerator->enumerate(enumerator, &host))
{
if (local)
{
@@ -413,6 +414,7 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
host = this->ike_sa->get_other_host(this->ike_sa);
}
}
+ enumerator->destroy(enumerator);
list = this->config->get_traffic_selectors(this->config, local,
supplied, host);
if (list->get_first(list, (void**)&ts) == SUCCESS)
@@ -831,6 +833,30 @@ static void check_for_rekeyed_child(private_quick_mode_t *this)
enumerator->destroy(enumerator);
}
+/**
+ * Get host to use for dynamic traffic selectors
+ */
+static host_t *get_dynamic_host(ike_sa_t *ike_sa, bool local)
+{
+ enumerator_t *enumerator;
+ host_t *host;
+
+ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
+ if (!enumerator->enumerate(enumerator, &host))
+ {
+ if (local)
+ {
+ host = ike_sa->get_my_host(ike_sa);
+ }
+ else
+ {
+ host = ike_sa->get_other_host(ike_sa);
+ }
+ }
+ enumerator->destroy(enumerator);
+ return host;
+}
+
METHOD(task_t, process_r, status_t,
private_quick_mode_t *this, message_t *message)
{
@@ -841,7 +867,6 @@ METHOD(task_t, process_r, status_t,
sa_payload_t *sa_payload;
linked_list_t *tsi, *tsr, *list = NULL;
peer_cfg_t *peer_cfg;
- host_t *me, *other;
u_int16_t group;
bool private;
@@ -849,16 +874,6 @@ METHOD(task_t, process_r, status_t,
{
return FAILED;
}
- me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
- if (!me)
- {
- me = this->ike_sa->get_my_host(this->ike_sa);
- }
- other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
- if (!other)
- {
- other = this->ike_sa->get_other_host(this->ike_sa);
- }
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
tsi = linked_list_create();
tsr = linked_list_create();
@@ -866,7 +881,8 @@ METHOD(task_t, process_r, status_t,
tsr->insert_last(tsr, this->tsr);
this->tsi = this->tsr = NULL;
this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
- me, other);
+ get_dynamic_host(this->ike_sa, TRUE),
+ get_dynamic_host(this->ike_sa, FALSE));
if (this->config)
{
this->tsi = select_ts(this, FALSE, tsi);
diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
index 2c282dc06..aa0644033 100644
--- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2006-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -186,9 +187,9 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
if (this->method)
{
action = "initiating";
- type = this->method->get_type(this->method, &vendor);
if (this->method->initiate(this->method, &out) == NEED_MORE)
{
+ type = this->method->get_type(this->method, &vendor);
if (vendor)
{
DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method (id 0x%02X)",
@@ -201,6 +202,8 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
}
return out;
}
+ /* type might have changed for virtual methods */
+ type = this->method->get_type(this->method, &vendor);
}
if (vendor)
{
@@ -233,9 +236,10 @@ static void replace_eap_identity(private_eap_authenticator_t *this)
static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
eap_payload_t *in)
{
- eap_type_t type, received_type;
- u_int32_t vendor, received_vendor;
+ eap_type_t type, received_type, conf_type;
+ u_int32_t vendor, received_vendor, conf_vendor;
eap_payload_t *out;
+ auth_cfg_t *auth;
if (in->get_code(in) != EAP_RESPONSE)
{
@@ -250,15 +254,25 @@ static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
{
if (received_vendor == 0 && received_type == EAP_NAK)
{
- DBG1(DBG_IKE, "received %N, sending %N",
- eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
+ auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
+ conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
+ conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
+ if ((type == EAP_IDENTITY && !vendor) ||
+ (type == conf_type && vendor == conf_vendor))
+ {
+ DBG1(DBG_IKE, "received %N, sending %N",
+ eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
+ return eap_payload_create_code(EAP_FAILURE,
+ in->get_identifier(in));
+ }
+ /* virtual methods handle NAKs in process() */
}
else
{
DBG1(DBG_IKE, "received invalid EAP response, sending %N",
eap_code_names, EAP_FAILURE);
+ return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
}
- return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
}
switch (this->method->process(this->method, in, &out))
@@ -302,6 +316,8 @@ static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
case FAILED:
default:
+ /* type might have changed for virtual methods */
+ type = this->method->get_type(this->method, &vendor);
if (vendor)
{
DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for "
@@ -324,8 +340,8 @@ static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
eap_payload_t *in)
{
- eap_type_t type;
- u_int32_t vendor;
+ eap_type_t type, conf_type;
+ u_int32_t vendor, conf_vendor;
auth_cfg_t *auth;
eap_payload_t *out;
identification_t *id;
@@ -357,9 +373,11 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
this->method->destroy(this->method);
this->method = NULL;
}
+ /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no
+ * EAP method (types 3-253, 255) */
DBG1(DBG_IKE, "%N not supported, sending EAP_NAK",
eap_type_names, type);
- return eap_payload_create_nak(in->get_identifier(in));
+ return eap_payload_create_nak(in->get_identifier(in), 0, 0, FALSE);
}
if (this->method == NULL)
{
@@ -373,11 +391,31 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)",
eap_type_names, type, in->get_identifier(in));
}
+ auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
+ conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
+ conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
+ if (conf_type != EAP_NAK &&
+ (conf_type != type || conf_vendor != vendor))
+ {
+ if (conf_vendor)
+ {
+ DBG1(DBG_IKE, "requesting EAP method %d-%d, sending EAP_NAK",
+ conf_type, conf_vendor);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "requesting %N authentication, sending EAP_NAK",
+ eap_type_names, conf_type);
+ }
+ return eap_payload_create_nak(in->get_identifier(in), conf_type,
+ conf_vendor, in->is_expanded(in));
+ }
this->method = load_method(this, type, vendor, EAP_PEER);
if (!this->method)
{
DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
- return eap_payload_create_nak(in->get_identifier(in));
+ return eap_payload_create_nak(in->get_identifier(in), 0, 0,
+ in->is_expanded(in));
}
}
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 5c5468dab..d7d912fdc 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -285,6 +285,30 @@ static void schedule_inactivity_timeout(private_child_create_t *this)
}
/**
+ * Get host to use for dynamic traffic selectors
+ */
+static host_t *get_dynamic_host(ike_sa_t *ike_sa, bool local)
+{
+ enumerator_t *enumerator;
+ host_t *host;
+
+ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
+ if (!enumerator->enumerate(enumerator, &host))
+ {
+ if (local)
+ {
+ host = ike_sa->get_my_host(ike_sa);
+ }
+ else
+ {
+ host = ike_sa->get_other_host(ike_sa);
+ }
+ }
+ enumerator->destroy(enumerator);
+ return host;
+}
+
+/**
* Install a CHILD_SA for usage, return value:
* - FAILED: no acceptable proposal
* - INVALID_ARG: diffie hellman group inacceptable
@@ -298,7 +322,7 @@ static status_t select_and_install(private_child_create_t *this,
chunk_t encr_i = chunk_empty, encr_r = chunk_empty;
chunk_t integ_i = chunk_empty, integ_r = chunk_empty;
linked_list_t *my_ts, *other_ts;
- host_t *me, *other, *other_vip, *my_vip;
+ host_t *me, *other;
bool private;
if (this->proposals == NULL)
@@ -314,8 +338,6 @@ static status_t select_and_install(private_child_create_t *this,
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
- my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
- other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
private = this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN);
this->proposal = this->config->select_proposal(this->config,
@@ -354,15 +376,6 @@ static status_t select_and_install(private_child_create_t *this,
this->dh_group = MODP_NONE;
}
- if (my_vip == NULL)
- {
- my_vip = me;
- }
- if (other_vip == NULL)
- {
- other_vip = other;
- }
-
if (this->initiator)
{
nonce_i = this->my_nonce;
@@ -378,9 +391,9 @@ static status_t select_and_install(private_child_create_t *this,
other_ts = this->tsi;
}
my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts,
- my_vip);
+ get_dynamic_host(this->ike_sa, TRUE));
other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts,
- other_vip);
+ get_dynamic_host(this->ike_sa, FALSE));
if (this->initiator)
{
@@ -723,7 +736,8 @@ static void process_payloads(private_child_create_t *this, message_t *message)
METHOD(task_t, build_i, status_t,
private_child_create_t *this, message_t *message)
{
- host_t *me, *other, *vip;
+ enumerator_t *enumerator;
+ host_t *vip;
peer_cfg_t *peer_cfg;
switch (message->get_exchange_type(message))
@@ -763,22 +777,10 @@ METHOD(task_t, build_i, status_t,
this->config->get_name(this->config));
}
- /* reuse virtual IP if we already have one */
- me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
- if (me == NULL)
- {
- me = this->ike_sa->get_my_host(this->ike_sa);
- }
- other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
- if (other == NULL)
- {
- other = this->ike_sa->get_other_host(this->ike_sa);
- }
-
/* check if we want a virtual IP, but don't have one */
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- vip = peer_cfg->get_virtual_ip(peer_cfg);
- if (!this->reqid && vip)
+ enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg);
+ if (!this->reqid && enumerator->enumerate(enumerator, &vip))
{
/* propose a 0.0.0.0/0 or ::/0 subnet when we use virtual ip */
vip = host_create_any(vip->get_family(vip));
@@ -788,11 +790,12 @@ METHOD(task_t, build_i, status_t,
}
else
{ /* but narrow it for host2host / if we already have a vip */
- this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
- NULL, me);
+ this->tsi = this->config->get_traffic_selectors(this->config, TRUE, NULL,
+ get_dynamic_host(this->ike_sa, TRUE));
}
- this->tsr = this->config->get_traffic_selectors(this->config, FALSE,
- NULL, other);
+ enumerator->destroy(enumerator);
+ this->tsr = this->config->get_traffic_selectors(this->config, FALSE, NULL,
+ get_dynamic_host(this->ike_sa, FALSE));
if (this->packet_tsi)
{
@@ -948,20 +951,10 @@ METHOD(task_t, build_r, status_t,
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
if (!this->config && peer_cfg && this->tsi && this->tsr)
{
- host_t *me, *other;
-
- me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
- if (me == NULL)
- {
- me = this->ike_sa->get_my_host(this->ike_sa);
- }
- other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
- if (other == NULL)
- {
- other = this->ike_sa->get_other_host(this->ike_sa);
- }
- this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr,
- this->tsi, me, other);
+ this->config = peer_cfg->select_child_cfg(peer_cfg,
+ this->tsr, this->tsi,
+ get_dynamic_host(this->ike_sa, TRUE),
+ get_dynamic_host(this->ike_sa, FALSE));
}
if (this->config == NULL)
diff --git a/src/libcharon/sa/ikev2/tasks/ike_config.c b/src/libcharon/sa/ikev2/tasks/ike_config.c
index 932b02d42..e788bb5f9 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_config.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_config.c
@@ -43,9 +43,9 @@ struct private_ike_config_t {
bool initiator;
/**
- * virtual ip
+ * Received list of virtual IPs, host_t*
*/
- host_t *virtual_ip;
+ linked_list_t *vips;
/**
* list of attributes requested and its handler, entry_t
@@ -170,8 +170,7 @@ static void process_attribute(private_ike_config_t *this,
}
if (ip)
{
- DESTROY_IF(this->virtual_ip);
- this->virtual_ip = ip;
+ this->vips->insert_last(this->vips, ip);
}
break;
}
@@ -242,23 +241,45 @@ METHOD(task_t, build_i, status_t,
peer_cfg_t *config;
configuration_attribute_type_t type;
chunk_t data;
- host_t *vip;
+ linked_list_t *vips;
+ host_t *host;
+
+ vips = linked_list_create();
/* reuse virtual IP if we already have one */
- vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
- if (!vip)
+ enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
+ TRUE);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ vips->insert_last(vips, host);
+ }
+ enumerator->destroy(enumerator);
+
+ if (vips->get_count(vips) == 0)
{
config = this->ike_sa->get_peer_cfg(this->ike_sa);
- vip = config->get_virtual_ip(config);
+ enumerator = config->create_virtual_ip_enumerator(config);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ vips->insert_last(vips, host);
+ }
+ enumerator->destroy(enumerator);
}
- if (vip)
+
+ if (vips->get_count(vips))
{
cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST);
- cp->add_attribute(cp, build_vip(vip));
+ enumerator = vips->create_enumerator(vips);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ cp->add_attribute(cp, build_vip(host));
+ }
+ enumerator->destroy(enumerator);
}
- enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes,
- this->ike_sa->get_other_id(this->ike_sa), vip);
+ enumerator = hydra->attributes->create_initiator_enumerator(
+ hydra->attributes,
+ this->ike_sa->get_other_id(this->ike_sa), vips);
while (enumerator->enumerate(enumerator, &handler, &type, &data))
{
configuration_attribute_t *ca;
@@ -284,6 +305,8 @@ METHOD(task_t, build_i, status_t,
}
enumerator->destroy(enumerator);
+ vips->destroy(vips);
+
if (cp)
{
message->add_payload(message, (payload_t*)cp);
@@ -310,40 +333,75 @@ METHOD(task_t, build_r, status_t,
enumerator_t *enumerator;
configuration_attribute_type_t type;
chunk_t value;
- host_t *vip = NULL;
cp_payload_t *cp = NULL;
peer_cfg_t *config;
identification_t *id;
+ linked_list_t *vips, *pools;
+ host_t *requested;
id = this->ike_sa->get_other_eap_id(this->ike_sa);
-
config = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (this->virtual_ip)
+ vips = linked_list_create();
+ pools = linked_list_create();
+
+ enumerator = this->vips->create_enumerator(this->vips);
+ while (enumerator->enumerate(enumerator, &requested))
{
- DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
- if (config->get_pool(config))
+ enumerator_t *poolenum;
+ char *pool;
+ host_t *found = NULL;
+
+ /* query all pools until we get an address */
+ DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
+
+ poolenum = config->create_pool_enumerator(config);
+ while (poolenum->enumerate(poolenum, &pool))
{
- vip = hydra->attributes->acquire_address(hydra->attributes,
- config->get_pool(config), id, this->virtual_ip);
+ found = hydra->attributes->acquire_address(hydra->attributes,
+ pool, id, requested);
+ if (!found)
+ {
+ continue;
+ }
+ DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
+ this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
+ if (!cp)
+ {
+ cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY);
+ }
+ cp->add_attribute(cp, build_vip(found));
+ /* use pool to request other attributes */
+ if (pools->find_first(pools, NULL, (void**)&pool) == NOT_FOUND)
+ {
+ pools->insert_last(pools, pool);
+ }
+ vips->insert_last(vips, found);
+ break;
}
- if (vip == NULL)
+ poolenum->destroy(poolenum);
+
+ if (!found)
{
- DBG1(DBG_IKE, "no virtual IP found, sending %N",
- notify_type_names, INTERNAL_ADDRESS_FAILURE);
- message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
- chunk_empty);
- return SUCCESS;
+ DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
+ requested, id);
}
- DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id);
- this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
+ }
+ enumerator->destroy(enumerator);
- cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY);
- cp->add_attribute(cp, build_vip(vip));
+ if (this->vips->get_count(this->vips) && !vips->get_count(vips))
+ {
+ DBG1(DBG_IKE, "no virtual IP found, sending %N",
+ notify_type_names, INTERNAL_ADDRESS_FAILURE);
+ message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
+ chunk_empty);
+ vips->destroy_offset(vips, offsetof(host_t, destroy));
+ pools->destroy(pools);
+ return SUCCESS;
}
/* query registered providers for additional attributes to include */
enumerator = hydra->attributes->create_responder_enumerator(
- hydra->attributes, config->get_pool(config), id, vip);
+ hydra->attributes, pools, id, vips);
while (enumerator->enumerate(enumerator, &type, &value))
{
if (!cp)
@@ -357,12 +415,13 @@ METHOD(task_t, build_r, status_t,
type, value));
}
enumerator->destroy(enumerator);
+ vips->destroy_offset(vips, offsetof(host_t, destroy));
+ pools->destroy(pools);
if (cp)
{
message->add_payload(message, (payload_t*)cp);
}
- DESTROY_IF(vip);
return SUCCESS;
}
return NEED_MORE;
@@ -373,14 +432,20 @@ METHOD(task_t, process_i, status_t,
{
if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
{ /* in last IKE_AUTH exchange */
+ enumerator_t *enumerator;
+ host_t *host;
process_payloads(this, message);
- if (this->virtual_ip &&
- !this->virtual_ip->is_anyaddr(this->virtual_ip))
+ enumerator = this->vips->create_enumerator(this->vips);
+ while (enumerator->enumerate(enumerator, &host))
{
- this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
+ if (!host->is_anyaddr(host))
+ {
+ this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
+ }
}
+ enumerator->destroy(enumerator);
return SUCCESS;
}
return NEED_MORE;
@@ -395,10 +460,9 @@ METHOD(task_t, get_type, task_type_t,
METHOD(task_t, migrate, void,
private_ike_config_t *this, ike_sa_t *ike_sa)
{
- DESTROY_IF(this->virtual_ip);
-
this->ike_sa = ike_sa;
- this->virtual_ip = NULL;
+ this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
+ this->vips = linked_list_create();
this->requested->destroy_function(this->requested, free);
this->requested = linked_list_create();
}
@@ -406,7 +470,7 @@ METHOD(task_t, migrate, void,
METHOD(task_t, destroy, void,
private_ike_config_t *this)
{
- DESTROY_IF(this->virtual_ip);
+ this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
this->requested->destroy_function(this->requested, free);
free(this);
}
@@ -428,6 +492,7 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
},
.initiator = initiator,
.ike_sa = ike_sa,
+ .vips = linked_list_create(),
.requested = linked_list_create(),
);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
index 133bc296e..8c30ed96c 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
@@ -250,15 +250,26 @@ static void update_children(private_ike_mobike_t *this)
{
enumerator_t *enumerator;
child_sa_t *child_sa;
+ linked_list_t *vips;
+ host_t *host;
+
+ vips = linked_list_create();
+
+ enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ vips->insert_last(vips, host);
+ }
+ enumerator->destroy(enumerator);
enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
if (child_sa->update(child_sa,
this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa),
- this->ike_sa->get_virtual_ip(this->ike_sa, TRUE),
- this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED)
+ this->ike_sa->get_other_host(this->ike_sa), vips,
+ this->ike_sa->has_condition(this->ike_sa,
+ COND_NAT_ANY)) == NOT_SUPPORTED)
{
this->ike_sa->rekey_child_sa(this->ike_sa,
child_sa->get_protocol(child_sa),
@@ -266,6 +277,8 @@ static void update_children(private_ike_mobike_t *this)
}
}
enumerator->destroy(enumerator);
+
+ vips->destroy(vips);
}
/**
diff --git a/src/libhydra/attributes/attribute_handler.h b/src/libhydra/attributes/attribute_handler.h
index d042f47ef..6014ef0fa 100644
--- a/src/libhydra/attributes/attribute_handler.h
+++ b/src/libhydra/attributes/attribute_handler.h
@@ -22,8 +22,8 @@
#define ATTRIBUTE_HANDLER_H_
#include <chunk.h>
-#include <utils/host.h>
#include <utils/identification.h>
+#include <utils/linked_list.h>
#include "attributes.h"
@@ -62,11 +62,11 @@ struct attribute_handler_t {
* Enumerate attributes to request from a server.
*
* @param server server identity to request attributes from
- * @param vip virtual IP we are requesting, if any
+ * @param vips list of virtual IPs (host_t*) we are requesting
* @return enumerator (configuration_attribute_type_t, chunk_t)
*/
enumerator_t* (*create_attribute_enumerator)(attribute_handler_t *this,
- identification_t *server, host_t *vip);
+ identification_t *server, linked_list_t *vips);
};
#endif /** ATTRIBUTE_HANDLER_H_ @}*/
diff --git a/src/libhydra/attributes/attribute_manager.c b/src/libhydra/attributes/attribute_manager.c
index 95520531e..64dc9c7c9 100644
--- a/src/libhydra/attributes/attribute_manager.c
+++ b/src/libhydra/attributes/attribute_manager.c
@@ -51,12 +51,12 @@ struct private_attribute_manager_t {
* Data to pass to enumerator filters
*/
typedef struct {
- /** attribute group pool */
- char *pool;
+ /** attribute group pools */
+ linked_list_t *pools;
/** server/peer identity */
identification_t *id;
- /** requesting/assigned virtual IP */
- host_t *vip;
+ /** requesting/assigned virtual IPs */
+ linked_list_t *vips;
} enum_data_t;
METHOD(attribute_manager_t, acquire_address, host_t*,
@@ -80,14 +80,10 @@ METHOD(attribute_manager_t, acquire_address, host_t*,
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
- if (!host)
- {
- DBG1(DBG_CFG, "acquiring address from pool '%s' failed", pool);
- }
return host;
}
-METHOD(attribute_manager_t, release_address, void,
+METHOD(attribute_manager_t, release_address, bool,
private_attribute_manager_t *this, char *pool, host_t *address,
identification_t *id)
{
@@ -108,10 +104,7 @@ METHOD(attribute_manager_t, release_address, void,
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
- if (!found)
- {
- DBG1(DBG_CFG, "releasing address to pool '%s' failed", pool);
- }
+ return found;
}
/**
@@ -120,19 +113,21 @@ METHOD(attribute_manager_t, release_address, void,
static enumerator_t *responder_enum_create(attribute_provider_t *provider,
enum_data_t *data)
{
- return provider->create_attribute_enumerator(provider, data->pool,
- data->id, data->vip);
+ return provider->create_attribute_enumerator(provider, data->pools,
+ data->id, data->vips);
}
METHOD(attribute_manager_t, create_responder_enumerator, enumerator_t*,
- private_attribute_manager_t *this, char *pool, identification_t *id,
- host_t *vip)
+ private_attribute_manager_t *this, linked_list_t *pools,
+ identification_t *id, linked_list_t *vips)
{
- enum_data_t *data = malloc_thing(enum_data_t);
+ enum_data_t *data;
- data->pool = pool;
- data->id = id;
- data->vip = vip;
+ INIT(data,
+ .pools = pools,
+ .id = id,
+ .vips = vips,
+ );
this->lock->read_lock(this->lock);
return enumerator_create_cleaner(
enumerator_create_nested(
@@ -238,8 +233,8 @@ typedef struct {
enumerator_t *inner;
/** server ID we want attributes for */
identification_t *id;
- /** virtual IP we are requesting along with attriubutes */
- host_t *vip;
+ /** virtual IPs we are requesting along with attriubutes */
+ linked_list_t *vips;
} initiator_enumerator_t;
/**
@@ -259,7 +254,7 @@ static bool initiator_enumerate(initiator_enumerator_t *this,
}
DESTROY_IF(this->inner);
this->inner = this->handler->create_attribute_enumerator(this->handler,
- this->id, this->vip);
+ this->id, this->vips);
}
/* inject the handler as additional attribute */
*handler = this->handler;
@@ -278,20 +273,22 @@ static void initiator_destroy(initiator_enumerator_t *this)
}
METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*,
- private_attribute_manager_t *this, identification_t *id, host_t *vip)
+ private_attribute_manager_t *this, identification_t *id, linked_list_t *vips)
{
- initiator_enumerator_t *enumerator = malloc_thing(initiator_enumerator_t);
+ initiator_enumerator_t *enumerator;
this->lock->read_lock(this->lock);
- enumerator->public.enumerate = (void*)initiator_enumerate;
- enumerator->public.destroy = (void*)initiator_destroy;
- enumerator->this = this;
- enumerator->id = id;
- enumerator->vip = vip;
- enumerator->outer = this->handlers->create_enumerator(this->handlers);
- enumerator->inner = NULL;
- enumerator->handler = NULL;
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)initiator_enumerate,
+ .destroy = (void*)initiator_destroy,
+ },
+ .this = this,
+ .id = id,
+ .vips = vips,
+ .outer = this->handlers->create_enumerator(this->handlers),
+ );
return &enumerator->public;
}
diff --git a/src/libhydra/attributes/attribute_manager.h b/src/libhydra/attributes/attribute_manager.h
index 56afef7c6..8bc80ca11 100644
--- a/src/libhydra/attributes/attribute_manager.h
+++ b/src/libhydra/attributes/attribute_manager.h
@@ -54,20 +54,22 @@ struct attribute_manager_t {
* @param pool pool name from which the address was acquired
* @param address address to release
* @param id peer identity to get address for
+ * @return TRUE if address released to pool
*/
- void (*release_address)(attribute_manager_t *this,
+ bool (*release_address)(attribute_manager_t *this,
char *pool, host_t *address, identification_t *id);
/**
* Create an enumerator over attributes to hand out to a peer.
*
- * @param pool pool name to get attributes from
+ * @param pool list of pools names (char*) to query attributes from
* @param id peer identity to hand out attributes to
- * @param vip virtual IP to assign to peer, if any
+ * @param vip list of virtual IPs (host_t*) to assign to peer
* @return enumerator (configuration_attribute_type_t, chunk_t)
*/
enumerator_t* (*create_responder_enumerator)(attribute_manager_t *this,
- char *pool, identification_t *id, host_t *vip);
+ linked_list_t *pool, identification_t *id,
+ linked_list_t *vips);
/**
* Register an attribute provider to the manager.
@@ -114,11 +116,11 @@ struct attribute_manager_t {
* Create an enumerator over attributes to request from server.
*
* @param id server identity to hand out attributes to
- * @param vip virtual IP going to request, if any
+ * @param vip list of virtual IPs (host_t*) going to request
* @return enumerator (attribute_handler_t, ca_type_t, chunk_t)
*/
enumerator_t* (*create_initiator_enumerator)(attribute_manager_t *this,
- identification_t *id, host_t *vip);
+ identification_t *id, linked_list_t *vips);
/**
* Register an attribute handler to the manager.
diff --git a/src/libhydra/attributes/attribute_provider.h b/src/libhydra/attributes/attribute_provider.h
index e4b4e13f3..327135ffe 100644
--- a/src/libhydra/attributes/attribute_provider.h
+++ b/src/libhydra/attributes/attribute_provider.h
@@ -23,6 +23,7 @@
#include <utils/host.h>
#include <utils/identification.h>
+#include <utils/linked_list.h>
typedef struct attribute_provider_t attribute_provider_t;
@@ -56,13 +57,14 @@ struct attribute_provider_t {
/**
* Create an enumerator over attributes to hand out to a peer.
*
- * @param pool pool name to get attributes from
+ * @param pool list of pools names (char*) to query attributes from
* @param id peer ID
- * @param vip virtual IP to assign to peer, if any
+ * @param vip list of virtual IPs (host_t*) to assign to peer
* @return enumerator (configuration_attribute_type_t, chunk_t)
*/
enumerator_t* (*create_attribute_enumerator)(attribute_provider_t *this,
- char *pool, identification_t *id, host_t *vip);
+ linked_list_t *pools, identification_t *id,
+ linked_list_t *vips);
};
#endif /** ATTRIBUTE_PROVIDER_H_ @}*/
diff --git a/src/libhydra/attributes/mem_pool.c b/src/libhydra/attributes/mem_pool.c
index f55b3a7d1..b2fed2703 100644
--- a/src/libhydra/attributes/mem_pool.c
+++ b/src/libhydra/attributes/mem_pool.c
@@ -162,6 +162,12 @@ METHOD(mem_pool_t, get_name, const char*,
return this->name;
}
+METHOD(mem_pool_t, get_base, host_t*,
+ private_mem_pool_t *this)
+{
+ return this->base;
+}
+
METHOD(mem_pool_t, get_size, u_int,
private_mem_pool_t *this)
{
@@ -220,11 +226,9 @@ METHOD(mem_pool_t, acquire_address, host_t*,
return requested->clone(requested);
}
- if (!requested->is_anyaddr(requested) &&
- requested->get_family(requested) !=
+ if (requested->get_family(requested) !=
this->base->get_family(this->base))
{
- DBG1(DBG_CFG, "IP pool address family mismatch");
return NULL;
}
@@ -463,6 +467,7 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
INIT(this,
.public = {
.get_name = _get_name,
+ .get_base = _get_base,
.get_size = _get_size,
.get_online = _get_online,
.get_offline = _get_offline,
diff --git a/src/libhydra/attributes/mem_pool.h b/src/libhydra/attributes/mem_pool.h
index bb963de93..7b7e58af7 100644
--- a/src/libhydra/attributes/mem_pool.h
+++ b/src/libhydra/attributes/mem_pool.h
@@ -39,6 +39,13 @@ struct mem_pool_t {
const char* (*get_name)(mem_pool_t *this);
/**
+ * Get the base (first) address of this pool.
+ *
+ * @return base address, internal host
+ */
+ host_t* (*get_base)(mem_pool_t *this);
+
+ /**
* Get the size (i.e. number of addresses) of this pool.
*
* @return the size of this pool
diff --git a/src/libhydra/plugins/attr/attr_provider.c b/src/libhydra/plugins/attr/attr_provider.c
index 6af8b473b..673c72116 100644
--- a/src/libhydra/plugins/attr/attr_provider.c
+++ b/src/libhydra/plugins/attr/attr_provider.c
@@ -77,10 +77,10 @@ static bool attr_enum_filter(void *null, attribute_entry_t **in,
}
METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
- private_attr_provider_t *this, char *pool,
- identification_t *id, host_t *vip)
+ private_attr_provider_t *this, linked_list_t *pools,
+ identification_t *id, linked_list_t *vips)
{
- if (vip)
+ if (vips->get_count(vips))
{
this->lock->read_lock(this->lock);
return enumerator_create_filter(
diff --git a/src/libhydra/plugins/attr_sql/sql_attribute.c b/src/libhydra/plugins/attr_sql/sql_attribute.c
index 714bbcd72..8055be71c 100644
--- a/src/libhydra/plugins/attr_sql/sql_attribute.c
+++ b/src/libhydra/plugins/attr_sql/sql_attribute.c
@@ -233,7 +233,7 @@ static host_t* get_lease(private_sql_attribute_t *this, char *name,
}
METHOD(attribute_provider_t, acquire_address, host_t*,
- private_sql_attribute_t *this, char *names, identification_t *id,
+ private_sql_attribute_t *this, char *name, identification_t *id,
host_t *requested)
{
host_t *address = NULL;
@@ -242,59 +242,17 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
identity = get_identity(this, id);
if (identity)
{
- /* check for a single pool first (no concatenation and enumeration) */
- if (strchr(names, ',') == NULL)
+ pool = get_pool(this, name, &timeout);
+ if (pool)
{
- pool = get_pool(this, names, &timeout);
- if (pool)
+ /* check for an existing lease */
+ address = check_lease(this, name, pool, identity);
+ if (address == NULL)
{
- /* check for an existing lease */
- address = check_lease(this, names, pool, identity);
- if (address == NULL)
- {
- /* get an unallocated address or expired lease */
- address = get_lease(this, names, pool, timeout, identity);
- }
+ /* get an unallocated address or expired lease */
+ address = get_lease(this, name, pool, timeout, identity);
}
}
- else
- {
- enumerator_t *enumerator;
- char *name;
-
- /* in a first step check for an existing lease over all pools */
- enumerator = enumerator_create_token(names, ",", " ");
- while (enumerator->enumerate(enumerator, &name))
- {
- pool = get_pool(this, name, &timeout);
- if (pool)
- {
- address = check_lease(this, name, pool, identity);
- if (address)
- {
- enumerator->destroy(enumerator);
- return address;
- }
- }
- }
- enumerator->destroy(enumerator);
-
- /* in a second step get an unallocated address or expired lease */
- enumerator = enumerator_create_token(names, ",", " ");
- while (enumerator->enumerate(enumerator, &name))
- {
- pool = get_pool(this, name, &timeout);
- if (pool)
- {
- address = get_lease(this, name, pool, timeout, identity);
- if (address)
- {
- break;
- }
- }
- }
- enumerator->destroy(enumerator);
- }
}
return address;
}
@@ -303,50 +261,41 @@ METHOD(attribute_provider_t, release_address, bool,
private_sql_attribute_t *this, char *name, host_t *address,
identification_t *id)
{
- enumerator_t *enumerator;
- bool found = FALSE;
+ u_int pool, timeout;
time_t now = time(NULL);
- enumerator = enumerator_create_token(name, ",", " ");
- while (enumerator->enumerate(enumerator, &name))
+ pool = get_pool(this, name, &timeout);
+ if (pool)
{
- u_int pool, timeout;
-
- pool = get_pool(this, name, &timeout);
- if (pool)
+ if (this->history)
{
- if (this->history)
- {
- this->db->execute(this->db, NULL,
- "INSERT INTO leases (address, identity, acquired, released)"
- " SELECT id, identity, acquired, ? FROM addresses "
- " WHERE pool = ? AND address = ?",
- DB_UINT, now, DB_UINT, pool,
- DB_BLOB, address->get_address(address));
- }
- if (this->db->execute(this->db, NULL,
- "UPDATE addresses SET released = ? WHERE "
- "pool = ? AND address = ?", DB_UINT, time(NULL),
- DB_UINT, pool, DB_BLOB, address->get_address(address)) > 0)
- {
- found = TRUE;
- break;
- }
+ this->db->execute(this->db, NULL,
+ "INSERT INTO leases (address, identity, acquired, released)"
+ " SELECT id, identity, acquired, ? FROM addresses "
+ " WHERE pool = ? AND address = ?",
+ DB_UINT, now, DB_UINT, pool,
+ DB_BLOB, address->get_address(address));
+ }
+ if (this->db->execute(this->db, NULL,
+ "UPDATE addresses SET released = ? WHERE "
+ "pool = ? AND address = ?", DB_UINT, time(NULL),
+ DB_UINT, pool, DB_BLOB, address->get_address(address)) > 0)
+ {
+ return TRUE;
}
}
- enumerator->destroy(enumerator);
- return found;
+ return FALSE;
}
METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
- private_sql_attribute_t *this, char *names, identification_t *id,
- host_t *vip)
+ private_sql_attribute_t *this, linked_list_t *pools, identification_t *id,
+ linked_list_t *vips)
{
enumerator_t *attr_enumerator = NULL;
- if (vip)
+ if (vips->get_count(vips))
{
- enumerator_t *names_enumerator;
+ enumerator_t *pool_enumerator;
u_int count;
char *name;
@@ -357,8 +306,8 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
{
u_int identity = get_identity(this, id);
- names_enumerator = enumerator_create_token(names, ",", " ");
- while (names_enumerator->enumerate(names_enumerator, &name))
+ pool_enumerator = pools->create_enumerator(pools);
+ while (pool_enumerator->enumerate(pool_enumerator, &name))
{
u_int attr_pool = get_attr_pool(this, name);
if (!attr_pool)
@@ -385,14 +334,14 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
DESTROY_IF(attr_enumerator);
attr_enumerator = NULL;
}
- names_enumerator->destroy(names_enumerator);
+ pool_enumerator->destroy(pool_enumerator);
}
/* in a second step check for attributes that match name */
if (!attr_enumerator)
{
- names_enumerator = enumerator_create_token(names, ",", " ");
- while (names_enumerator->enumerate(names_enumerator, &name))
+ pool_enumerator = pools->create_enumerator(pools);
+ while (pool_enumerator->enumerate(pool_enumerator, &name))
{
u_int attr_pool = get_attr_pool(this, name);
if (!attr_pool)
@@ -419,7 +368,7 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
DESTROY_IF(attr_enumerator);
attr_enumerator = NULL;
}
- names_enumerator->destroy(names_enumerator);
+ pool_enumerator->destroy(pool_enumerator);
}
this->db->execute(this->db, NULL, "END TRANSACTION");
diff --git a/src/libhydra/plugins/resolve/resolve_handler.c b/src/libhydra/plugins/resolve/resolve_handler.c
index 011ebbaaf..2bee45d0d 100644
--- a/src/libhydra/plugins/resolve/resolve_handler.c
+++ b/src/libhydra/plugins/resolve/resolve_handler.c
@@ -267,46 +267,71 @@ METHOD(attribute_handler_t, release, void,
typedef struct {
/** implements enumerator_t interface */
enumerator_t public;
- /** virtual IP we are requesting */
- host_t *vip;
+ /** request IPv4 DNS? */
+ bool v4;
+ /** request IPv6 DNS? */
+ bool v6;
} attribute_enumerator_t;
static bool attribute_enumerate(attribute_enumerator_t *this,
configuration_attribute_type_t *type,
chunk_t *data)
{
- switch (this->vip->get_family(this->vip))
+ if (this->v4)
{
- case AF_INET:
- *type = INTERNAL_IP4_DNS;
- break;
- case AF_INET6:
- *type = INTERNAL_IP6_DNS;
- break;
- default:
- return FALSE;
+ *type = INTERNAL_IP4_DNS;
+ *data = chunk_empty;
+ this->v4 = FALSE;
+ return TRUE;
}
- *data = chunk_empty;
- /* enumerate only once */
- this->public.enumerate = (void*)return_false;
- return TRUE;
+ if (this->v6)
+ {
+ *type = INTERNAL_IP6_DNS;
+ *data = chunk_empty;
+ this->v6 = FALSE;
+ return TRUE;
+ }
+ return FALSE;
}
-METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
- private_resolve_handler_t *this, identification_t *server, host_t *vip)
+/**
+ * Check if a list has a host of given family
+ */
+static bool has_host_family(linked_list_t *list, int family)
{
- if (vip)
+ enumerator_t *enumerator;
+ host_t *host;
+ bool found = FALSE;
+
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &host))
{
- attribute_enumerator_t *enumerator;
+ if (host->get_family(host) == family)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
- enumerator = malloc_thing(attribute_enumerator_t);
- enumerator->public.enumerate = (void*)attribute_enumerate;
- enumerator->public.destroy = (void*)free;
- enumerator->vip = vip;
+ return found;
+}
- return &enumerator->public;
- }
- return enumerator_create_empty();
+METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
+ private_resolve_handler_t *this, identification_t *server,
+ linked_list_t *vips)
+{
+ attribute_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)attribute_enumerate,
+ .destroy = (void*)free,
+ },
+ .v4 = has_host_family(vips, AF_INET),
+ .v6 = has_host_family(vips, AF_INET6),
+ );
+ return &enumerator->public;
}
METHOD(resolve_handler_t, destroy, void,
diff --git a/src/libipsec/esp_context.c b/src/libipsec/esp_context.c
index c7fb7ab2f..dc3ad3f8b 100644
--- a/src/libipsec/esp_context.c
+++ b/src/libipsec/esp_context.c
@@ -16,6 +16,7 @@
*/
#include <limits.h>
+#include <stdint.h>
#include "esp_context.h"
diff --git a/src/libipsec/ip_packet.c b/src/libipsec/ip_packet.c
index 4593ba5c8..52aeaa209 100644
--- a/src/libipsec/ip_packet.c
+++ b/src/libipsec/ip_packet.c
@@ -130,19 +130,19 @@ ip_packet_t *ip_packet_create(chunk_t packet)
{
case 4:
{
- struct iphdr *ip;
+ struct ip *ip;
- if (packet.len < sizeof(struct iphdr))
+ if (packet.len < sizeof(struct ip))
{
DBG1(DBG_ESP, "IPv4 packet too short");
goto failed;
}
- ip = (struct iphdr*)packet.ptr;
+ ip = (struct ip*)packet.ptr;
src = host_create_from_chunk(AF_INET,
- chunk_from_thing(ip->saddr), 0);
+ chunk_from_thing(ip->ip_src), 0);
dst = host_create_from_chunk(AF_INET,
- chunk_from_thing(ip->daddr), 0);
- next_header = ip->protocol;
+ chunk_from_thing(ip->ip_dst), 0);
+ next_header = ip->ip_p;
break;
}
#ifdef HAVE_NETINET_IP6_H
diff --git a/src/libstrongswan/eap/eap.c b/src/libstrongswan/eap/eap.c
index efd3ee981..1e4cf11bf 100644
--- a/src/libstrongswan/eap/eap.c
+++ b/src/libstrongswan/eap/eap.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -13,8 +14,13 @@
* for more details.
*/
+#include <stdlib.h>
+#include <errno.h>
+
#include "eap.h"
+#include <debug.h>
+
ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE,
"EAP_REQUEST",
"EAP_RESPONSE",
@@ -51,12 +57,12 @@ ENUM_NEXT(eap_type_names, EAP_MSTLV, EAP_MSTLV, EAP_MSCHAPV2,
"EAP_MSTLV");
ENUM_NEXT(eap_type_names, EAP_TNC, EAP_TNC, EAP_MSTLV,
"EAP_TNC");
-ENUM_NEXT(eap_type_names, EAP_DYNAMIC, EAP_EXPERIMENTAL, EAP_TNC,
- "EAP_DYNAMIC",
- "EAP_RADIUS",
+ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_TNC,
"EAP_EXPANDED",
- "EAP_EXPERIMENTAL");
-ENUM_END(eap_type_names, EAP_EXPERIMENTAL);
+ "EAP_EXPERIMENTAL",
+ "EAP_RADIUS",
+ "EAP_DYNAMIC");
+ENUM_END(eap_type_names, EAP_DYNAMIC);
ENUM_BEGIN(eap_type_short_names, EAP_IDENTITY, EAP_GTC,
"ID",
@@ -80,12 +86,12 @@ ENUM_NEXT(eap_type_short_names, EAP_MSTLV, EAP_MSTLV, EAP_MSCHAPV2,
"MSTLV");
ENUM_NEXT(eap_type_short_names, EAP_TNC, EAP_TNC, EAP_MSTLV,
"TNC");
-ENUM_NEXT(eap_type_short_names, EAP_DYNAMIC, EAP_EXPERIMENTAL, EAP_TNC,
- "DYN",
- "RAD",
+ENUM_NEXT(eap_type_short_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_TNC,
"EXP",
- "XP");
-ENUM_END(eap_type_short_names, EAP_EXPERIMENTAL);
+ "XP",
+ "RAD",
+ "DYN");
+ENUM_END(eap_type_short_names, EAP_DYNAMIC);
/*
* See header
@@ -108,6 +114,7 @@ eap_type_t eap_type_from_string(char *name)
{"peap", EAP_PEAP},
{"mschapv2", EAP_MSCHAPV2},
{"tnc", EAP_TNC},
+ {"dynamic", EAP_DYNAMIC},
{"radius", EAP_RADIUS},
};
@@ -120,3 +127,56 @@ eap_type_t eap_type_from_string(char *name)
}
return 0;
}
+
+/*
+ * See header
+ */
+eap_vendor_type_t *eap_vendor_type_from_string(char *str)
+{
+ enumerator_t *enumerator;
+ eap_vendor_type_t *result = NULL;
+ eap_type_t type = 0;
+ u_int32_t vendor = 0;
+ char *part, *end;
+
+ /* parse EAP method string of the form: [eap-]type[-vendor] */
+ enumerator = enumerator_create_token(str, "-", " ");
+ while (enumerator->enumerate(enumerator, &part))
+ {
+ if (!type)
+ {
+ if (streq(part, "eap"))
+ { /* skip 'eap' at the beginning */
+ continue;
+ }
+ type = eap_type_from_string(part);
+ if (!type)
+ {
+ type = strtoul(part, &end, 0);
+ if (*end != '\0' || errno)
+ {
+ DBG1(DBG_LIB, "unknown or invalid EAP method: %s", part);
+ break;
+ }
+ }
+ continue;
+ }
+ vendor = strtoul(part, &end, 0);
+ if (*end != '\0' || errno)
+ {
+ DBG1(DBG_LIB, "invalid EAP vendor: %s", part);
+ type = 0;
+ }
+ break;
+ }
+ enumerator->destroy(enumerator);
+
+ if (type)
+ {
+ INIT(result,
+ .type = type,
+ .vendor = vendor,
+ );
+ }
+ return result;
+}
diff --git a/src/libstrongswan/eap/eap.h b/src/libstrongswan/eap/eap.h
index 143232e4b..0e144b123 100644
--- a/src/libstrongswan/eap/eap.h
+++ b/src/libstrongswan/eap/eap.h
@@ -1,6 +1,8 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG
+ * 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
@@ -23,6 +25,7 @@
typedef enum eap_code_t eap_code_t;
typedef enum eap_type_t eap_type_t;
+typedef struct eap_vendor_type_t eap_vendor_type_t;
#include <library.h>
@@ -64,12 +67,12 @@ enum eap_type_t {
EAP_MSCHAPV2 = 26,
EAP_MSTLV = 33,
EAP_TNC = 38,
- /** select EAP method dynamically based on i.e. EAP-Identity */
- EAP_DYNAMIC = 252,
- /** not a method, but an implementation providing different methods */
- EAP_RADIUS = 253,
EAP_EXPANDED = 254,
EAP_EXPERIMENTAL = 255,
+ /** not a method, but an implementation providing different methods */
+ EAP_RADIUS = 256,
+ /** not a method, select method dynamically based on client selection */
+ EAP_DYNAMIC = 257,
};
/**
@@ -83,6 +86,22 @@ extern enum_name_t *eap_type_names;
extern enum_name_t *eap_type_short_names;
/**
+ * Struct that stores EAP type and vendor ID
+ */
+struct eap_vendor_type_t {
+
+ /**
+ * EAP type
+ */
+ eap_type_t type;
+
+ /**
+ * Vendor Id
+ */
+ u_int32_t vendor;
+};
+
+/**
* EAP packet format
*/
typedef struct __attribute__((packed)) {
@@ -101,4 +120,12 @@ typedef struct __attribute__((packed)) {
*/
eap_type_t eap_type_from_string(char *name);
+/**
+ * Parse a string of the form [eap-]type[-vendor].
+ *
+ * @param str EAP method string
+ * @return parsed type (gets allocated), NULL if unknown or failed
+ */
+eap_vendor_type_t *eap_vendor_type_from_string(char *str);
+
#endif /** EAP_H_ @}*/
diff --git a/src/libstrongswan/utils/tun_device.c b/src/libstrongswan/utils/tun_device.c
index 889fe6247..36f3359c0 100644
--- a/src/libstrongswan/utils/tun_device.c
+++ b/src/libstrongswan/utils/tun_device.c
@@ -3,6 +3,7 @@
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2012 Martin Willi
*
* 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
@@ -24,8 +25,17 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <linux/if.h>
+#include <net/if.h>
+
+#ifdef __APPLE__
+#include <net/if_utun.h>
+#include <netinet/in_var.h>
+#include <sys/kern_control.h>
+#elif defined(__linux__)
#include <linux/if_tun.h>
+#else
+#include <net/if_tun.h>
+#endif
#include "tun_device.h"
@@ -127,6 +137,14 @@ METHOD(tun_device_t, set_address, bool,
this->if_name, strerror(errno));
return FALSE;
}
+#ifdef __APPLE__
+ if (ioctl(this->sock, SIOCSIFDSTADDR, &ifr) < 0)
+ {
+ DBG1(DBG_LIB, "failed to set dest address on %s: %s",
+ this->if_name, strerror(errno));
+ return FALSE;
+ }
+#endif /* __APPLE__ */
set_netmask(&ifr, family, netmask);
@@ -176,6 +194,8 @@ METHOD(tun_device_t, set_mtu, bool,
if (ioctl(this->sock, SIOCSIFMTU, &ifr) < 0)
{
+ DBG1(DBG_LIB, "failed to set MTU on %s: %s", this->if_name,
+ strerror(errno));
return FALSE;
}
this->mtu = mtu;
@@ -269,6 +289,20 @@ METHOD(tun_device_t, destroy, void,
if (this->tunfd > 0)
{
close(this->tunfd);
+#ifdef __FreeBSD__
+ /* tun(4) says the following: "These network interfaces persist until
+ * the if_tun.ko module is unloaded, or until removed with the
+ * ifconfig(8) command." So simply closing the FD is not enough. */
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
+ if (ioctl(this->sock, SIOCIFDESTROY, &ifr) < 0)
+ {
+ DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name,
+ strerror(errno));
+ }
+#endif /* __FreeBSD__ */
}
if (this->sock > 0)
{
@@ -278,18 +312,70 @@ METHOD(tun_device_t, destroy, void,
}
/**
- * Allocate a TUN device
+ * Initialize the tun device
*/
-static int tun_alloc(char dev[IFNAMSIZ])
+static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
{
+#ifdef __APPLE__
+
+ struct ctl_info info;
+ struct sockaddr_ctl addr;
+ socklen_t size = IFNAMSIZ;
+
+ memset(&info, 0, sizeof(info));
+ memset(&addr, 0, sizeof(addr));
+
+ this->tunfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (this->tunfd < 0)
+ {
+ DBG1(DBG_LIB, "failed to open tundevice PF_SYSTEM socket: %s",
+ strerror(errno));
+ return FALSE;
+ }
+
+ /* get a control identifier for the utun kernel extension */
+ strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME));
+ if (ioctl(this->tunfd, CTLIOCGINFO, &info) < 0)
+ {
+ DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno));
+ close(this->tunfd);
+ return FALSE;
+ }
+
+ addr.sc_id = info.ctl_id;
+ addr.sc_len = sizeof(addr);
+ addr.sc_family = AF_SYSTEM;
+ addr.ss_sysaddr = AF_SYS_CONTROL;
+ /* allocate identifier dynamically */
+ addr.sc_unit = 0;
+
+ if (connect(this->tunfd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
+ {
+ DBG1(DBG_LIB, "failed to connect tundevice: %s", strerror(errno));
+ close(this->tunfd);
+ return FALSE;
+ }
+ if (getsockopt(this->tunfd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
+ this->if_name, &size) < 0)
+ {
+ DBG1(DBG_LIB, "getting tundevice name failed: %s", strerror(errno));
+ close(this->tunfd);
+ return FALSE;
+ }
+ return TRUE;
+
+#elif defined(IFF_TUN)
+
struct ifreq ifr;
- int fd;
- fd = open("/dev/net/tun", O_RDWR);
- if (fd < 0)
+ strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ);
+ this->if_name[IFNAMSIZ-1] = '\0';
+
+ this->tunfd = open("/dev/net/tun", O_RDWR);
+ if (this->tunfd < 0)
{
DBG1(DBG_LIB, "failed to open /dev/net/tun: %s", strerror(errno));
- return fd;
+ return FALSE;
}
memset(&ifr, 0, sizeof(ifr));
@@ -297,16 +383,42 @@ static int tun_alloc(char dev[IFNAMSIZ])
/* TUN device, no packet info */
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
- strncpy(ifr.ifr_name, dev, IFNAMSIZ);
-
- if (ioctl(fd, TUNSETIFF, (void*)&ifr) < 0)
+ strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
+ if (ioctl(this->tunfd, TUNSETIFF, (void*)&ifr) < 0)
{
DBG1(DBG_LIB, "failed to configure TUN device: %s", strerror(errno));
- close(fd);
- return -1;
+ close(this->tunfd);
+ return FALSE;
+ }
+ strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ);
+ return TRUE;
+
+#else /* !IFF_TUN */
+
+ /* this works on FreeBSD and might also work on Linux with older TUN
+ * driver versions (no IFF_TUN) */
+ char devname[IFNAMSIZ];
+ int i;
+
+ if (name_tmpl)
+ {
+ DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported");
}
- strncpy(dev, ifr.ifr_name, IFNAMSIZ);
- return fd;
+
+ for (i = 0; i < 256; i++)
+ {
+ snprintf(devname, IFNAMSIZ, "/dev/tun%d", i);
+ this->tunfd = open(devname, O_RDWR);
+ if (this->tunfd > 0)
+ { /* for ioctl(2) calls only the interface name is used */
+ snprintf(this->if_name, IFNAMSIZ, "tun%d", i);
+ break;
+ }
+ DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno));
+ }
+ return this->tunfd > 0;
+
+#endif /* !__APPLE__ */
}
/*
@@ -331,13 +443,9 @@ tun_device_t *tun_device_create(const char *name_tmpl)
.sock = -1,
);
- strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ);
- this->if_name[IFNAMSIZ-1] = '\0';
-
- this->tunfd = tun_alloc(this->if_name);
- if (this->tunfd < 0)
+ if (!init_tun(this, name_tmpl))
{
- destroy(this);
+ free(this);
return NULL;
}
DBG1(DBG_LIB, "created TUN device: %s", this->if_name);
diff --git a/src/starter/args.c b/src/starter/args.c
index 640cc43d6..eb25b2abb 100644
--- a/src/starter/args.c
+++ b/src/starter/args.c
@@ -186,7 +186,7 @@ static const token_info_t token_info[] =
{ ARG_STR, offsetof(starter_end_t, subnet), NULL },
{ ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
{ ARG_STR, offsetof(starter_end_t, sourceip), NULL },
- { ARG_MISC, 0, NULL /* KW_NATIP */ },
+ { ARG_STR, offsetof(starter_end_t, dns), NULL },
{ ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
{ ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
{ ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool },
diff --git a/src/starter/cmp.c b/src/starter/cmp.c
index 724dc7804..aaba7b11d 100644
--- a/src/starter/cmp.c
+++ b/src/starter/cmp.c
@@ -26,7 +26,6 @@ static bool starter_cmp_end(starter_end_t *c1, starter_end_t *c2)
if ((c1 == NULL) || (c2 == NULL))
return FALSE;
- VARCMP(has_natip);
VARCMP(modecfg);
VARCMP(port);
VARCMP(protocol);
diff --git a/src/starter/confread.c b/src/starter/confread.c
index 642fc551b..f30f2188c 100644
--- a/src/starter/confread.c
+++ b/src/starter/confread.c
@@ -231,64 +231,6 @@ static void kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token,
end->host = strdupnull(value);
break;
case KW_SOURCEIP:
- if (end->has_natip)
- {
- DBG1(DBG_APP, "# natip and sourceip cannot be defined at the same time");
- goto err;
- }
- if (value[0] == '%')
- {
- if (streq(value, "%modeconfig") || streq(value, "%modecfg") ||
- streq(value, "%config") || streq(value, "%cfg"))
- {
- /* request ip via config payload */
- free(end->sourceip);
- end->sourceip = NULL;
- end->sourceip_mask = 1;
- }
- else
- { /* %poolname, strip %, serve ip requests */
- free(end->sourceip);
- end->sourceip = strdupnull(value+1);
- end->sourceip_mask = 0;
- }
- end->modecfg = TRUE;
- }
- else
- {
- host_t *host;
- char *sep;
-
- sep = strchr(value, '/');
- if (sep)
- { /* CIDR notation, address pool */
- *sep = '\0';
- host = host_create_from_string(value, 0);
- if (!host)
- {
- DBG1(DBG_APP, "# bad subnet: %s=%s", name, value);
- goto err;
- }
- host->destroy(host);
- free(end->sourceip);
- end->sourceip = strdupnull(value);
- end->sourceip_mask = atoi(sep + 1);
- /* restore the original text in case also= is used */
- *sep = '/';
- }
- else
- { /* fixed srcip */
- host = host_create_from_string(value, 0);
- if (!host)
- {
- DBG1(DBG_APP, "# bad addr: %s=%s", name, value);
- goto err;
- }
- end->sourceip_mask = (host->get_family(host) == AF_INET) ?
- 32 : 128;
- host->destroy(host);
- }
- }
conn->mode = MODE_TUNNEL;
conn->proxy_mode = FALSE;
break;
@@ -370,27 +312,6 @@ static void kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token,
}
break;
}
- case KW_NATIP:
- {
- host_t *host;
- if (end->sourceip)
- {
- DBG1(DBG_APP, "# natip and sourceip cannot be defined at the same time");
- goto err;
- }
- host = host_create_from_string(value, 0);
- if (!host)
- {
- DBG1(DBG_APP, "# bad addr: %s=%s", name, value);
- goto err;
- }
- host->destroy(host);
- end->sourceip = strdupnull(value);
- end->has_natip = TRUE;
- conn->mode = MODE_TUNNEL;
- conn->proxy_mode = FALSE;
- break;
- }
default:
break;
}
diff --git a/src/starter/confread.h b/src/starter/confread.h
index 0c284229b..3f2079883 100644
--- a/src/starter/confread.h
+++ b/src/starter/confread.h
@@ -102,7 +102,6 @@ struct starter_end {
char *host;
u_int ikeport;
char *subnet;
- bool has_natip;
bool modecfg;
certpolicy_t sendcert;
bool firewall;
@@ -112,7 +111,7 @@ struct starter_end {
u_int16_t port;
u_int8_t protocol;
char *sourceip;
- int sourceip_mask;
+ char *dns;
};
typedef struct also also_t;
diff --git a/src/starter/keywords.h b/src/starter/keywords.h
index bd9affe6c..537bceb07 100644
--- a/src/starter/keywords.h
+++ b/src/starter/keywords.h
@@ -97,7 +97,7 @@ typedef enum {
KW_SUBNET,
KW_PROTOPORT,
KW_SOURCEIP,
- KW_NATIP,
+ KW_DNS,
KW_FIREWALL,
KW_HOSTACCESS,
KW_ALLOWANY,
@@ -126,7 +126,7 @@ typedef enum {
KW_LEFTSUBNET,
KW_LEFTPROTOPORT,
KW_LEFTSOURCEIP,
- KW_LEFTNATIP,
+ KW_LEFTDNS,
KW_LEFTFIREWALL,
KW_LEFTHOSTACCESS,
KW_LEFTALLOWANY,
@@ -155,7 +155,7 @@ typedef enum {
KW_RIGHTSUBNET,
KW_RIGHTPROTOPORT,
KW_RIGHTSOURCEIP,
- KW_RIGHTNATIP,
+ KW_RIGHTDNS,
KW_RIGHTFIREWALL,
KW_RIGHTHOSTACCESS,
KW_RIGHTALLOWANY,
diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt
index 30d89f924..8366f5209 100644
--- a/src/starter/keywords.txt
+++ b/src/starter/keywords.txt
@@ -85,7 +85,7 @@ leftsubnet, KW_LEFTSUBNET
leftsubnetwithin, KW_LEFTSUBNET
leftprotoport, KW_LEFTPROTOPORT
leftsourceip, KW_LEFTSOURCEIP
-leftnatip, KW_LEFTNATIP
+leftdns, KW_LEFTDNS
leftfirewall, KW_LEFTFIREWALL
lefthostaccess, KW_LEFTHOSTACCESS
leftallowany, KW_LEFTALLOWANY
@@ -109,7 +109,7 @@ rightsubnet, KW_RIGHTSUBNET
rightsubnetwithin, KW_RIGHTSUBNET
rightprotoport, KW_RIGHTPROTOPORT
rightsourceip, KW_RIGHTSOURCEIP
-rightnatip, KW_RIGHTNATIP
+rightdns, KW_RIGHTDNS
rightfirewall, KW_RIGHTFIREWALL
righthostaccess, KW_RIGHTHOSTACCESS
rightallowany, KW_RIGHTALLOWANY
diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c
index 0fbc5d245..d6ad3eb89 100644
--- a/src/starter/starterstroke.c
+++ b/src/starter/starterstroke.c
@@ -140,7 +140,7 @@ static void starter_stroke_add_end(stroke_msg_t *msg, stroke_end_t *msg_end, sta
msg_end->ikeport = conn_end->ikeport;
msg_end->subnets = push_string(msg, conn_end->subnet);
msg_end->sourceip = push_string(msg, conn_end->sourceip);
- msg_end->sourceip_mask = conn_end->sourceip_mask;
+ msg_end->dns = push_string(msg, conn_end->dns);
msg_end->sendcert = conn_end->sendcert;
msg_end->hostaccess = conn_end->hostaccess;
msg_end->tohost = !conn_end->subnet;
diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h
index 95de7d69b..662feed69 100644
--- a/src/stroke/stroke_msg.h
+++ b/src/stroke/stroke_msg.h
@@ -158,7 +158,7 @@ struct stroke_end_t {
char *address;
u_int16_t ikeport;
char *sourceip;
- int sourceip_mask;
+ char *dns;
char *subnets;
int sendcert;
int hostaccess;