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;
67 * Authentication method(s) to use/expect from initiator
72 * Authentication method(s) use/expected from responder
77 * Initiator ID to enforce
82 * Initiator ID to to match against as responder
84 char *initiator_match
;
87 * Responder ID to enforce
92 * Traffic Selector on initiator side, as proposed from initiator
97 * Traffic Selector on responder side, as proposed from initiator
102 * Traffic Selector on initiator side, as narrowed by responder
107 * Traffic Selector on responder side, as narrowed by responder
112 * IKE_SA rekeying delay
117 * CHILD_SA rekeying delay
127 * DPD timeout (IKEv1 only)
132 * incremental numbering of generated configs
137 * Dynamic source port, if used
142 * IKE version to use for load testing
144 ike_version_t version
;
147 * List of pools to allocate external addresses dynamically, as mem_pool_t
149 linked_list_t
*pools
;
152 * Address prefix to use when installing dynamic addresses
157 * Hashtable with leases in "pools", host_t => entry_t
162 * Mutex for leases hashtable
171 /** host reference, equal to key */
173 /** associated identity */
174 identification_t
*id
;
180 static void entry_destroy(entry_t
*this)
182 this->host
->destroy(this->host
);
183 this->id
->destroy(this->id
);
188 * Hashtable hash function
190 static u_int
hash(host_t
*key
)
192 return chunk_hash(key
->get_address(key
));
196 * Hashtable equals function
198 static bool equals(host_t
*a
, host_t
*b
)
200 return a
->ip_equals(a
, b
);
204 * Load external addresses to use, if any
206 static void load_addrs(private_load_tester_config_t
*this)
208 enumerator_t
*enumerator
, *tokens
;
211 char *iface
, *token
, *pos
;
214 this->prefix
= lib
->settings
->get_int(lib
->settings
,
215 "%s.plugins.load-tester.addrs_prefix", 16, charon
->name
);
216 enumerator
= lib
->settings
->create_key_value_enumerator(lib
->settings
,
217 "%s.plugins.load-tester.addrs", charon
->name
);
218 while (enumerator
->enumerate(enumerator
, &iface
, &token
))
220 tokens
= enumerator_create_token(token
, ",", " ");
221 while (tokens
->enumerate(tokens
, &token
))
223 pos
= strchr(token
, '-');
227 /* trim whitespace */
232 while (token
[strlen(token
) - 1] == ' ')
234 token
[strlen(token
) - 1] = '\0';
236 from
= host_create_from_string(token
, 0);
237 to
= host_create_from_string(pos
, 0);
240 pool
= mem_pool_create_range(iface
, from
, to
);
243 DBG1(DBG_CFG
, "loaded load-tester address range "
244 "%H-%H on %s", from
, to
, iface
);
245 this->pools
->insert_last(this->pools
, pool
);
252 DBG1(DBG_CFG
, "parsing load-tester address range %s-%s "
253 "failed, skipped", token
, pos
);
260 from
= host_create_from_subnet(token
, &bits
);
263 DBG1(DBG_CFG
, "loaded load-tester address pool %H/%d on %s",
265 pool
= mem_pool_create(iface
, from
, bits
);
267 this->pools
->insert_last(this->pools
, pool
);
271 DBG1(DBG_CFG
, "parsing load-tester address %s failed, "
276 tokens
->destroy(tokens
);
278 enumerator
->destroy(enumerator
);
282 * Generate auth config from string
284 static void generate_auth_cfg(private_load_tester_config_t
*this, char *str
,
285 peer_cfg_t
*peer_cfg
, bool local
, int num
)
287 enumerator_t
*enumerator
;
289 identification_t
*id
;
295 enumerator
= enumerator_create_token(str
, "|", " ");
296 while (enumerator
->enumerate(enumerator
, &str
))
299 auth
= auth_cfg_create();
302 if (this->initiator_id
)
304 if (this->initiator_match
&& (!local
&& !num
))
305 { /* as responder, use the secified identity that matches
306 * all used initiator identities, if given. */
307 snprintf(buf
, sizeof(buf
), this->initiator_match
, rnd
);
308 id
= identification_create_from_string(buf
);
310 else if ((local
&& num
) || (!local
&& !num
))
311 { /* as initiator, create peer specific identities */
312 snprintf(buf
, sizeof(buf
), this->initiator_id
, num
, rnd
);
313 id
= identification_create_from_string(buf
);
316 if (this->responder_id
)
318 if ((local
&& !num
) || (!local
&& num
))
320 snprintf(buf
, sizeof(buf
), this->responder_id
, num
, rnd
);
321 id
= identification_create_from_string(buf
);
325 if (streq(str
, "psk"))
326 { /* PSK authentication, use FQDNs */
327 class = AUTH_CLASS_PSK
;
330 if ((local
&& !num
) || (!local
&& num
))
332 id
= identification_create_from_string("srv.strongswan.org");
336 snprintf(buf
, sizeof(buf
), "c%d-r%d.strongswan.org",
338 id
= identification_create_from_string(buf
);
342 id
= identification_create_from_string("*.strongswan.org");
346 else if (strneq(str
, "eap", strlen("eap")))
347 { /* EAP authentication, use a NAI */
348 class = AUTH_CLASS_EAP
;
349 if (*(str
+ strlen("eap")) == '-')
351 type
= eap_type_from_string(str
+ strlen("eap-"));
354 auth
->add(auth
, AUTH_RULE_EAP_TYPE
, type
);
361 snprintf(buf
, sizeof(buf
), "1%.10d%.4d@strongswan.org",
363 id
= identification_create_from_string(buf
);
367 id
= identification_create_from_encoding(ID_ANY
, chunk_empty
);
373 if (!streq(str
, "pubkey"))
375 DBG1(DBG_CFG
, "invalid authentication: '%s', fallback to pubkey",
378 /* certificate authentication, use distinguished names */
379 class = AUTH_CLASS_PUBKEY
;
382 if ((local
&& !num
) || (!local
&& num
))
384 id
= identification_create_from_string(
385 "CN=srv, OU=load-test, O=strongSwan");
389 snprintf(buf
, sizeof(buf
),
390 "CN=c%d-r%d, OU=load-test, O=strongSwan", num
, rnd
);
391 id
= identification_create_from_string(buf
);
395 id
= identification_create_from_string(
396 "CN=*, OU=load-test, O=strongSwan");
400 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, class);
401 auth
->add(auth
, AUTH_RULE_IDENTITY
, id
);
402 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, local
);
404 enumerator
->destroy(enumerator
);
408 * Add a TS from a string to a child_cfg
410 static void add_ts(char *string
, child_cfg_t
*cfg
, bool local
)
412 traffic_selector_t
*ts
;
416 ts
= traffic_selector_create_from_cidr(string
, 0, 0, 65535);
419 DBG1(DBG_CFG
, "parsing TS string '%s' failed", string
);
424 ts
= traffic_selector_create_dynamic(0, 0, 65535);
428 cfg
->add_traffic_selector(cfg
, local
, ts
);
433 * Allocate and install a dynamic external address to use
435 static host_t
*allocate_addr(private_load_tester_config_t
*this, uint num
)
437 enumerator_t
*enumerator
;
439 host_t
*found
= NULL
, *requested
;
440 identification_t
*id
;
441 char *iface
= NULL
, buf
[32];
444 requested
= host_create_any(AF_INET
);
445 snprintf(buf
, sizeof(buf
), "ext-%d", num
);
446 id
= identification_create_from_string(buf
);
447 enumerator
= this->pools
->create_enumerator(this->pools
);
448 while (enumerator
->enumerate(enumerator
, &pool
))
450 found
= pool
->acquire_address(pool
, id
, requested
, MEM_POOL_NEW
);
453 iface
= (char*)pool
->get_name(pool
);
457 enumerator
->destroy(enumerator
);
458 requested
->destroy(requested
);
462 DBG1(DBG_CFG
, "no address found to install as load-tester external IP");
466 if (hydra
->kernel_interface
->add_ip(hydra
->kernel_interface
,
467 found
, this->prefix
, iface
) != SUCCESS
)
469 DBG1(DBG_CFG
, "installing load-tester IP %H on %s failed", found
, iface
);
470 found
->destroy(found
);
474 DBG1(DBG_CFG
, "installed load-tester IP %H on %s", found
, iface
);
476 .host
= found
->clone(found
),
479 this->mutex
->lock(this->mutex
);
480 entry
= this->leases
->put(this->leases
, entry
->host
, entry
);
481 this->mutex
->unlock(this->mutex
);
483 { /* shouldn't actually happen */
484 entry_destroy(entry
);
490 * Generate a new initiator config, num = 0 for responder config
492 static peer_cfg_t
* generate_config(private_load_tester_config_t
*this, uint num
)
495 child_cfg_t
*child_cfg
;
496 peer_cfg_t
*peer_cfg
;
497 proposal_t
*proposal
;
498 char local
[32], *remote
;
500 lifetime_cfg_t lifetime
= {
502 .life
= this->child_rekey
* 2,
503 .rekey
= this->child_rekey
,
510 if (this->pools
->get_count(this->pools
))
511 { /* using dynamically installed external addresses */
512 addr
= allocate_addr(this, num
);
515 DBG1(DBG_CFG
, "allocating external address failed");
518 snprintf(local
, sizeof(local
), "%H", addr
);
523 snprintf(local
, sizeof(local
), "%s", this->initiator
);
525 remote
= this->responder
;
529 snprintf(local
, sizeof(local
), "%s", this->responder
);
530 remote
= this->initiator
;
533 if (this->port
&& num
)
535 ike_cfg
= ike_cfg_create(this->version
, TRUE
, FALSE
,
536 local
, FALSE
, this->port
+ num
- 1,
537 remote
, FALSE
, IKEV2_NATT_PORT
,
538 FRAGMENTATION_NO
, 0);
542 ike_cfg
= ike_cfg_create(this->version
, TRUE
, FALSE
,
544 charon
->socket
->get_port(charon
->socket
, FALSE
),
545 remote
, FALSE
, IKEV2_UDP_PORT
,
546 FRAGMENTATION_NO
, 0);
548 ike_cfg
->add_proposal(ike_cfg
, this->proposal
->clone(this->proposal
));
549 peer_cfg
= peer_cfg_create("load-test", ike_cfg
,
550 CERT_SEND_IF_ASKED
, UNIQUE_NO
, 1, /* keytries */
551 this->ike_rekey
, 0, /* rekey, reauth */
552 0, this->ike_rekey
, /* jitter, overtime */
553 FALSE
, FALSE
, /* mobike, aggressive mode */
554 this->dpd_delay
, /* dpd_delay */
555 this->dpd_timeout
, /* dpd_timeout */
559 peer_cfg
->add_virtual_ip(peer_cfg
, this->vip
->clone(this->vip
));
563 peer_cfg
->add_pool(peer_cfg
, this->pool
);
567 generate_auth_cfg(this, this->initiator_auth
, peer_cfg
, TRUE
, num
);
568 generate_auth_cfg(this, this->responder_auth
, peer_cfg
, FALSE
, num
);
572 generate_auth_cfg(this, this->responder_auth
, peer_cfg
, TRUE
, num
);
573 generate_auth_cfg(this, this->initiator_auth
, peer_cfg
, FALSE
, num
);
576 child_cfg
= child_cfg_create("load-test", &lifetime
, NULL
, TRUE
, MODE_TUNNEL
,
577 ACTION_NONE
, ACTION_NONE
, ACTION_NONE
, FALSE
,
578 0, 0, NULL
, NULL
, 0);
579 proposal
= proposal_create_from_string(PROTO_ESP
, "aes128-sha1");
580 child_cfg
->add_proposal(child_cfg
, proposal
);
586 add_ts(NULL
, child_cfg
, TRUE
);
590 add_ts(this->initiator_tsi
, child_cfg
, TRUE
);
592 add_ts(this->initiator_tsr
, child_cfg
, FALSE
);
596 add_ts(this->responder_tsr
, child_cfg
, TRUE
);
597 add_ts(this->responder_tsi
, child_cfg
, FALSE
);
599 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
);
603 METHOD(backend_t
, create_peer_cfg_enumerator
, enumerator_t
*,
604 private_load_tester_config_t
*this,
605 identification_t
*me
, identification_t
*other
)
607 return enumerator_create_single(this->peer_cfg
, NULL
);
610 METHOD(backend_t
, create_ike_cfg_enumerator
, enumerator_t
*,
611 private_load_tester_config_t
*this, host_t
*me
, host_t
*other
)
615 ike_cfg
= this->peer_cfg
->get_ike_cfg(this->peer_cfg
);
616 return enumerator_create_single(ike_cfg
, NULL
);
619 METHOD(backend_t
, get_peer_cfg_by_name
, peer_cfg_t
*,
620 private_load_tester_config_t
*this, char *name
)
622 if (streq(name
, "load-test"))
624 return generate_config(this, this->num
++);
629 METHOD(load_tester_config_t
, delete_ip
, void,
630 private_load_tester_config_t
*this, host_t
*ip
)
632 enumerator_t
*enumerator
;
636 this->mutex
->lock(this->mutex
);
637 entry
= this->leases
->remove(this->leases
, ip
);
638 this->mutex
->unlock(this->mutex
);
642 enumerator
= this->pools
->create_enumerator(this->pools
);
643 while (enumerator
->enumerate(enumerator
, &pool
))
645 if (pool
->release_address(pool
, entry
->host
, entry
->id
))
647 hydra
->kernel_interface
->del_ip(hydra
->kernel_interface
,
648 entry
->host
, this->prefix
, FALSE
);
652 enumerator
->destroy(enumerator
);
653 entry_destroy(entry
);
657 METHOD(load_tester_config_t
, destroy
, void,
658 private_load_tester_config_t
*this)
660 this->mutex
->destroy(this->mutex
);
661 this->leases
->destroy(this->leases
);
662 this->pools
->destroy_offset(this->pools
, offsetof(mem_pool_t
, destroy
));
663 this->peer_cfg
->destroy(this->peer_cfg
);
664 DESTROY_IF(this->proposal
);
665 DESTROY_IF(this->vip
);
670 * Described in header.
672 load_tester_config_t
*load_tester_config_create()
674 private_load_tester_config_t
*this;
679 .create_peer_cfg_enumerator
= _create_peer_cfg_enumerator
,
680 .create_ike_cfg_enumerator
= _create_ike_cfg_enumerator
,
681 .get_peer_cfg_by_name
= _get_peer_cfg_by_name
,
683 .delete_ip
= _delete_ip
,
686 .pools
= linked_list_create(),
687 .leases
= hashtable_create((hashtable_hash_t
)hash
,
688 (hashtable_equals_t
)equals
, 256),
689 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
693 if (lib
->settings
->get_bool(lib
->settings
,
694 "%s.plugins.load-tester.request_virtual_ip", FALSE
, charon
->name
))
696 this->vip
= host_create_from_string("0.0.0.0", 0);
698 this->pool
= lib
->settings
->get_str(lib
->settings
,
699 "%s.plugins.load-tester.pool", NULL
, charon
->name
);
700 this->initiator
= lib
->settings
->get_str(lib
->settings
,
701 "%s.plugins.load-tester.initiator", "0.0.0.0", charon
->name
);
702 this->responder
= lib
->settings
->get_str(lib
->settings
,
703 "%s.plugins.load-tester.responder", "127.0.0.1", charon
->name
);
705 this->proposal
= proposal_create_from_string(PROTO_IKE
,
706 lib
->settings
->get_str(lib
->settings
,
707 "%s.plugins.load-tester.proposal", "aes128-sha1-modp768",
711 this->proposal
= proposal_create_from_string(PROTO_IKE
,
712 "aes128-sha1-modp768");
714 this->ike_rekey
= lib
->settings
->get_int(lib
->settings
,
715 "%s.plugins.load-tester.ike_rekey", 0, charon
->name
);
716 this->child_rekey
= lib
->settings
->get_int(lib
->settings
,
717 "%s.plugins.load-tester.child_rekey", 600, charon
->name
);
718 this->dpd_delay
= lib
->settings
->get_int(lib
->settings
,
719 "%s.plugins.load-tester.dpd_delay", 0, charon
->name
);
720 this->dpd_timeout
= lib
->settings
->get_int(lib
->settings
,
721 "%s.plugins.load-tester.dpd_timeout", 0, charon
->name
);
723 this->initiator_auth
= lib
->settings
->get_str(lib
->settings
,
724 "%s.plugins.load-tester.initiator_auth", "pubkey", charon
->name
);
725 this->responder_auth
= lib
->settings
->get_str(lib
->settings
,
726 "%s.plugins.load-tester.responder_auth", "pubkey", charon
->name
);
727 this->initiator_id
= lib
->settings
->get_str(lib
->settings
,
728 "%s.plugins.load-tester.initiator_id", NULL
, charon
->name
);
729 this->initiator_match
= lib
->settings
->get_str(lib
->settings
,
730 "%s.plugins.load-tester.initiator_match", NULL
, charon
->name
);
731 this->responder_id
= lib
->settings
->get_str(lib
->settings
,
732 "%s.plugins.load-tester.responder_id", NULL
, charon
->name
);
734 this->initiator_tsi
= lib
->settings
->get_str(lib
->settings
,
735 "%s.plugins.load-tester.initiator_tsi", NULL
, charon
->name
);
736 this->responder_tsi
=lib
->settings
->get_str(lib
->settings
,
737 "%s.plugins.load-tester.responder_tsi",
738 this->initiator_tsi
, charon
->name
);
739 this->initiator_tsr
= lib
->settings
->get_str(lib
->settings
,
740 "%s.plugins.load-tester.initiator_tsr", NULL
, charon
->name
);
741 this->responder_tsr
=lib
->settings
->get_str(lib
->settings
,
742 "%s.plugins.load-tester.responder_tsr",
743 this->initiator_tsr
, charon
->name
);
745 this->port
= lib
->settings
->get_int(lib
->settings
,
746 "%s.plugins.load-tester.dynamic_port", 0, charon
->name
);
747 this->version
= lib
->settings
->get_int(lib
->settings
,
748 "%s.plugins.load-tester.version", IKE_ANY
, charon
->name
);
752 this->peer_cfg
= generate_config(this, 0);
754 return &this->public;