2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "load_tester_config.h"
20 #include <attributes/mem_pool.h>
21 #include <collections/hashtable.h>
22 #include <threading/mutex.h>
24 typedef struct private_load_tester_config_t private_load_tester_config_t
;
27 * Private data of an load_tester_config_t object
29 struct private_load_tester_config_t
{
34 load_tester_config_t
public;
72 * Authentication method(s) to use/expect from initiator
77 * Authentication method(s) use/expected from responder
82 * Initiator ID to enforce
87 * Initiator ID to to match against as responder
89 char *initiator_match
;
92 * Responder ID to enforce
97 * Traffic Selector on initiator side, as proposed from initiator
102 * Traffic Selector on responder side, as proposed from initiator
107 * Traffic Selector on initiator side, as narrowed by responder
112 * Traffic Selector on responder side, as narrowed by responder
117 * IKE_SA rekeying delay
122 * CHILD_SA rekeying delay
132 * DPD timeout (IKEv1 only)
137 * incremental numbering of generated configs
142 * Dynamic source port, if used
147 * IKE version to use for load testing
149 ike_version_t version
;
152 * List of pools to allocate external addresses dynamically, as mem_pool_t
154 linked_list_t
*pools
;
157 * Address prefix to use when installing dynamic addresses
162 * Hashtable with leases in "pools", host_t => entry_t
167 * Mutex for leases hashtable
176 /** host reference, equal to key */
178 /** associated identity */
179 identification_t
*id
;
185 static void entry_destroy(entry_t
*this)
187 this->host
->destroy(this->host
);
188 this->id
->destroy(this->id
);
193 * Hashtable hash function
195 static u_int
hash(host_t
*key
)
197 return chunk_hash(key
->get_address(key
));
201 * Hashtable equals function
203 static bool equals(host_t
*a
, host_t
*b
)
205 return a
->ip_equals(a
, b
);
209 * Load external addresses to use, if any
211 static void load_addrs(private_load_tester_config_t
*this)
213 enumerator_t
*enumerator
, *tokens
;
216 char *iface
, *token
, *pos
;
219 this->prefix
= lib
->settings
->get_int(lib
->settings
,
220 "%s.plugins.load-tester.addrs_prefix", 16, charon
->name
);
221 enumerator
= lib
->settings
->create_key_value_enumerator(lib
->settings
,
222 "%s.plugins.load-tester.addrs", charon
->name
);
223 while (enumerator
->enumerate(enumerator
, &iface
, &token
))
225 tokens
= enumerator_create_token(token
, ",", " ");
226 while (tokens
->enumerate(tokens
, &token
))
228 pos
= strchr(token
, '-');
232 /* trim whitespace */
237 while (token
[strlen(token
) - 1] == ' ')
239 token
[strlen(token
) - 1] = '\0';
241 from
= host_create_from_string(token
, 0);
242 to
= host_create_from_string(pos
, 0);
245 pool
= mem_pool_create_range(iface
, from
, to
);
248 DBG1(DBG_CFG
, "loaded load-tester address range "
249 "%H-%H on %s", from
, to
, iface
);
250 this->pools
->insert_last(this->pools
, pool
);
257 DBG1(DBG_CFG
, "parsing load-tester address range %s-%s "
258 "failed, skipped", token
, pos
);
265 from
= host_create_from_subnet(token
, &bits
);
268 DBG1(DBG_CFG
, "loaded load-tester address pool %H/%d on %s",
270 pool
= mem_pool_create(iface
, from
, bits
);
272 this->pools
->insert_last(this->pools
, pool
);
276 DBG1(DBG_CFG
, "parsing load-tester address %s failed, "
281 tokens
->destroy(tokens
);
283 enumerator
->destroy(enumerator
);
287 * Generate auth config from string
289 static void generate_auth_cfg(private_load_tester_config_t
*this, char *str
,
290 peer_cfg_t
*peer_cfg
, bool local
, int num
)
292 enumerator_t
*enumerator
;
294 identification_t
*id
;
300 enumerator
= enumerator_create_token(str
, "|", " ");
301 while (enumerator
->enumerate(enumerator
, &str
))
304 auth
= auth_cfg_create();
307 if (this->initiator_id
)
309 if (this->initiator_match
&& (!local
&& !num
))
310 { /* as responder, use the secified identity that matches
311 * all used initiator identities, if given. */
312 snprintf(buf
, sizeof(buf
), this->initiator_match
, rnd
);
313 id
= identification_create_from_string(buf
);
315 else if ((local
&& num
) || (!local
&& !num
))
316 { /* as initiator, create peer specific identities */
317 snprintf(buf
, sizeof(buf
), this->initiator_id
, num
, rnd
);
318 id
= identification_create_from_string(buf
);
321 if (this->responder_id
)
323 if ((local
&& !num
) || (!local
&& num
))
325 snprintf(buf
, sizeof(buf
), this->responder_id
, num
, rnd
);
326 id
= identification_create_from_string(buf
);
330 if (streq(str
, "psk"))
331 { /* PSK authentication, use FQDNs */
332 class = AUTH_CLASS_PSK
;
335 if ((local
&& !num
) || (!local
&& num
))
337 id
= identification_create_from_string("srv.strongswan.org");
341 snprintf(buf
, sizeof(buf
), "c%d-r%d.strongswan.org",
343 id
= identification_create_from_string(buf
);
347 id
= identification_create_from_string("*.strongswan.org");
351 else if (strneq(str
, "eap", strlen("eap")))
352 { /* EAP authentication, use a NAI */
353 class = AUTH_CLASS_EAP
;
354 if (*(str
+ strlen("eap")) == '-')
356 type
= eap_type_from_string(str
+ strlen("eap-"));
359 auth
->add(auth
, AUTH_RULE_EAP_TYPE
, type
);
366 snprintf(buf
, sizeof(buf
), "1%.10d%.4d@strongswan.org",
368 id
= identification_create_from_string(buf
);
372 id
= identification_create_from_encoding(ID_ANY
, chunk_empty
);
378 if (!streq(str
, "pubkey"))
380 DBG1(DBG_CFG
, "invalid authentication: '%s', fallback to pubkey",
383 /* certificate authentication, use distinguished names */
384 class = AUTH_CLASS_PUBKEY
;
387 if ((local
&& !num
) || (!local
&& num
))
389 id
= identification_create_from_string(
390 "CN=srv, OU=load-test, O=strongSwan");
394 snprintf(buf
, sizeof(buf
),
395 "CN=c%d-r%d, OU=load-test, O=strongSwan", num
, rnd
);
396 id
= identification_create_from_string(buf
);
400 id
= identification_create_from_string(
401 "CN=*, OU=load-test, O=strongSwan");
405 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, class);
406 auth
->add(auth
, AUTH_RULE_IDENTITY
, id
);
407 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, local
);
409 enumerator
->destroy(enumerator
);
413 * Add a TS from a string to a child_cfg
415 static void add_ts(char *string
, child_cfg_t
*cfg
, bool local
)
417 traffic_selector_t
*ts
;
421 ts
= traffic_selector_create_from_cidr(string
, 0, 0, 65535);
424 DBG1(DBG_CFG
, "parsing TS string '%s' failed", string
);
429 ts
= traffic_selector_create_dynamic(0, 0, 65535);
433 cfg
->add_traffic_selector(cfg
, local
, ts
);
438 * Allocate and install a dynamic external address to use
440 static host_t
*allocate_addr(private_load_tester_config_t
*this, uint num
)
442 enumerator_t
*enumerator
;
444 host_t
*found
= NULL
, *requested
;
445 identification_t
*id
;
446 char *iface
= NULL
, buf
[32];
449 requested
= host_create_any(AF_INET
);
450 snprintf(buf
, sizeof(buf
), "ext-%d", num
);
451 id
= identification_create_from_string(buf
);
452 enumerator
= this->pools
->create_enumerator(this->pools
);
453 while (enumerator
->enumerate(enumerator
, &pool
))
455 found
= pool
->acquire_address(pool
, id
, requested
, MEM_POOL_NEW
);
458 iface
= (char*)pool
->get_name(pool
);
462 enumerator
->destroy(enumerator
);
463 requested
->destroy(requested
);
467 DBG1(DBG_CFG
, "no address found to install as load-tester external IP");
471 if (hydra
->kernel_interface
->add_ip(hydra
->kernel_interface
,
472 found
, this->prefix
, iface
) != SUCCESS
)
474 DBG1(DBG_CFG
, "installing load-tester IP %H on %s failed", found
, iface
);
475 found
->destroy(found
);
479 DBG1(DBG_CFG
, "installed load-tester IP %H on %s", found
, iface
);
481 .host
= found
->clone(found
),
484 this->mutex
->lock(this->mutex
);
485 entry
= this->leases
->put(this->leases
, entry
->host
, entry
);
486 this->mutex
->unlock(this->mutex
);
488 { /* shouldn't actually happen */
489 entry_destroy(entry
);
495 * Generate a new initiator config, num = 0 for responder config
497 static peer_cfg_t
* generate_config(private_load_tester_config_t
*this, uint num
)
500 child_cfg_t
*child_cfg
;
501 peer_cfg_t
*peer_cfg
;
502 char local
[32], *remote
;
504 lifetime_cfg_t lifetime
= {
506 .life
= this->child_rekey
* 2,
507 .rekey
= this->child_rekey
,
514 if (this->pools
->get_count(this->pools
))
515 { /* using dynamically installed external addresses */
516 addr
= allocate_addr(this, num
);
519 DBG1(DBG_CFG
, "allocating external address failed");
522 snprintf(local
, sizeof(local
), "%H", addr
);
527 snprintf(local
, sizeof(local
), "%s", this->initiator
);
529 remote
= this->responder
;
533 snprintf(local
, sizeof(local
), "%s", this->responder
);
534 remote
= this->initiator
;
537 if (this->port
&& num
)
539 ike_cfg
= ike_cfg_create(this->version
, TRUE
, FALSE
,
540 local
, FALSE
, this->port
+ num
- 1,
541 remote
, FALSE
, IKEV2_NATT_PORT
,
542 FRAGMENTATION_NO
, 0);
546 ike_cfg
= ike_cfg_create(this->version
, TRUE
, FALSE
,
548 charon
->socket
->get_port(charon
->socket
, FALSE
),
549 remote
, FALSE
, IKEV2_UDP_PORT
,
550 FRAGMENTATION_NO
, 0);
552 ike_cfg
->add_proposal(ike_cfg
, this->proposal
->clone(this->proposal
));
553 peer_cfg
= peer_cfg_create("load-test", ike_cfg
,
554 CERT_SEND_IF_ASKED
, UNIQUE_NO
, 1, /* keytries */
555 this->ike_rekey
, 0, /* rekey, reauth */
556 0, this->ike_rekey
, /* jitter, overtime */
557 FALSE
, FALSE
, /* mobike, aggressive mode */
558 this->dpd_delay
, /* dpd_delay */
559 this->dpd_timeout
, /* dpd_timeout */
563 peer_cfg
->add_virtual_ip(peer_cfg
, this->vip
->clone(this->vip
));
567 peer_cfg
->add_pool(peer_cfg
, this->pool
);
571 generate_auth_cfg(this, this->initiator_auth
, peer_cfg
, TRUE
, num
);
572 generate_auth_cfg(this, this->responder_auth
, peer_cfg
, FALSE
, num
);
576 generate_auth_cfg(this, this->responder_auth
, peer_cfg
, TRUE
, num
);
577 generate_auth_cfg(this, this->initiator_auth
, peer_cfg
, FALSE
, num
);
580 child_cfg
= child_cfg_create("load-test", &lifetime
, NULL
, TRUE
, MODE_TUNNEL
,
581 ACTION_NONE
, ACTION_NONE
, ACTION_NONE
, FALSE
,
582 0, 0, NULL
, NULL
, 0);
583 child_cfg
->add_proposal(child_cfg
, this->esp
->clone(this->esp
));
589 add_ts(NULL
, child_cfg
, TRUE
);
593 add_ts(this->initiator_tsi
, child_cfg
, TRUE
);
595 add_ts(this->initiator_tsr
, child_cfg
, FALSE
);
599 add_ts(this->responder_tsr
, child_cfg
, TRUE
);
600 add_ts(this->responder_tsi
, child_cfg
, FALSE
);
602 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
);
606 METHOD(backend_t
, create_peer_cfg_enumerator
, enumerator_t
*,
607 private_load_tester_config_t
*this,
608 identification_t
*me
, identification_t
*other
)
610 return enumerator_create_single(this->peer_cfg
, NULL
);
613 METHOD(backend_t
, create_ike_cfg_enumerator
, enumerator_t
*,
614 private_load_tester_config_t
*this, host_t
*me
, host_t
*other
)
618 ike_cfg
= this->peer_cfg
->get_ike_cfg(this->peer_cfg
);
619 return enumerator_create_single(ike_cfg
, NULL
);
622 METHOD(backend_t
, get_peer_cfg_by_name
, peer_cfg_t
*,
623 private_load_tester_config_t
*this, char *name
)
625 if (streq(name
, "load-test"))
627 return generate_config(this, this->num
++);
632 METHOD(load_tester_config_t
, delete_ip
, void,
633 private_load_tester_config_t
*this, host_t
*ip
)
635 enumerator_t
*enumerator
;
639 this->mutex
->lock(this->mutex
);
640 entry
= this->leases
->remove(this->leases
, ip
);
641 this->mutex
->unlock(this->mutex
);
645 enumerator
= this->pools
->create_enumerator(this->pools
);
646 while (enumerator
->enumerate(enumerator
, &pool
))
648 if (pool
->release_address(pool
, entry
->host
, entry
->id
))
650 hydra
->kernel_interface
->del_ip(hydra
->kernel_interface
,
651 entry
->host
, this->prefix
, FALSE
);
655 enumerator
->destroy(enumerator
);
656 entry_destroy(entry
);
660 METHOD(load_tester_config_t
, destroy
, void,
661 private_load_tester_config_t
*this)
663 this->mutex
->destroy(this->mutex
);
664 this->leases
->destroy(this->leases
);
665 this->pools
->destroy_offset(this->pools
, offsetof(mem_pool_t
, destroy
));
666 this->peer_cfg
->destroy(this->peer_cfg
);
667 DESTROY_IF(this->proposal
);
668 DESTROY_IF(this->esp
);
669 DESTROY_IF(this->vip
);
674 * Described in header.
676 load_tester_config_t
*load_tester_config_create()
678 private_load_tester_config_t
*this;
683 .create_peer_cfg_enumerator
= _create_peer_cfg_enumerator
,
684 .create_ike_cfg_enumerator
= _create_ike_cfg_enumerator
,
685 .get_peer_cfg_by_name
= _get_peer_cfg_by_name
,
687 .delete_ip
= _delete_ip
,
690 .pools
= linked_list_create(),
691 .leases
= hashtable_create((hashtable_hash_t
)hash
,
692 (hashtable_equals_t
)equals
, 256),
693 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
697 if (lib
->settings
->get_bool(lib
->settings
,
698 "%s.plugins.load-tester.request_virtual_ip", FALSE
, charon
->name
))
700 this->vip
= host_create_from_string("0.0.0.0", 0);
702 this->pool
= lib
->settings
->get_str(lib
->settings
,
703 "%s.plugins.load-tester.pool", NULL
, charon
->name
);
704 this->initiator
= lib
->settings
->get_str(lib
->settings
,
705 "%s.plugins.load-tester.initiator", "0.0.0.0", charon
->name
);
706 this->responder
= lib
->settings
->get_str(lib
->settings
,
707 "%s.plugins.load-tester.responder", "127.0.0.1", charon
->name
);
709 this->proposal
= proposal_create_from_string(PROTO_IKE
,
710 lib
->settings
->get_str(lib
->settings
,
711 "%s.plugins.load-tester.proposal", "aes128-sha1-modp768",
715 this->proposal
= proposal_create_from_string(PROTO_IKE
,
716 "aes128-sha1-modp768");
718 this->esp
= proposal_create_from_string(PROTO_ESP
,
719 lib
->settings
->get_str(lib
->settings
,
720 "%s.plugins.load-tester.esp", "aes128-sha1",
724 this->esp
= proposal_create_from_string(PROTO_ESP
, "aes128-sha1");
727 this->ike_rekey
= lib
->settings
->get_int(lib
->settings
,
728 "%s.plugins.load-tester.ike_rekey", 0, charon
->name
);
729 this->child_rekey
= lib
->settings
->get_int(lib
->settings
,
730 "%s.plugins.load-tester.child_rekey", 600, charon
->name
);
731 this->dpd_delay
= lib
->settings
->get_int(lib
->settings
,
732 "%s.plugins.load-tester.dpd_delay", 0, charon
->name
);
733 this->dpd_timeout
= lib
->settings
->get_int(lib
->settings
,
734 "%s.plugins.load-tester.dpd_timeout", 0, charon
->name
);
736 this->initiator_auth
= lib
->settings
->get_str(lib
->settings
,
737 "%s.plugins.load-tester.initiator_auth", "pubkey", charon
->name
);
738 this->responder_auth
= lib
->settings
->get_str(lib
->settings
,
739 "%s.plugins.load-tester.responder_auth", "pubkey", charon
->name
);
740 this->initiator_id
= lib
->settings
->get_str(lib
->settings
,
741 "%s.plugins.load-tester.initiator_id", NULL
, charon
->name
);
742 this->initiator_match
= lib
->settings
->get_str(lib
->settings
,
743 "%s.plugins.load-tester.initiator_match", NULL
, charon
->name
);
744 this->responder_id
= lib
->settings
->get_str(lib
->settings
,
745 "%s.plugins.load-tester.responder_id", NULL
, charon
->name
);
747 this->initiator_tsi
= lib
->settings
->get_str(lib
->settings
,
748 "%s.plugins.load-tester.initiator_tsi", NULL
, charon
->name
);
749 this->responder_tsi
=lib
->settings
->get_str(lib
->settings
,
750 "%s.plugins.load-tester.responder_tsi",
751 this->initiator_tsi
, charon
->name
);
752 this->initiator_tsr
= lib
->settings
->get_str(lib
->settings
,
753 "%s.plugins.load-tester.initiator_tsr", NULL
, charon
->name
);
754 this->responder_tsr
=lib
->settings
->get_str(lib
->settings
,
755 "%s.plugins.load-tester.responder_tsr",
756 this->initiator_tsr
, charon
->name
);
758 this->port
= lib
->settings
->get_int(lib
->settings
,
759 "%s.plugins.load-tester.dynamic_port", 0, charon
->name
);
760 this->version
= lib
->settings
->get_int(lib
->settings
,
761 "%s.plugins.load-tester.version", IKE_ANY
, charon
->name
);
765 this->peer_cfg
= generate_config(this, 0);
767 return &this->public;