reuse reqid when a ROUTED child_sa gets INSTALLED
fixed a bug in retransmission code added support for the "keyingtries" ipsec.conf parameter added support for the "dpddelay" ipsec.conf parameter done some work for "dpdaction" behavior some other cleanups and fixes
This commit is contained in:
@@ -29,38 +29,77 @@
|
||||
|
||||
/**
|
||||
* Timeout in milliseconds after that a half open IKE_SA gets deleted.
|
||||
* Set to zero to disable
|
||||
*/
|
||||
#define HALF_OPEN_IKE_SA_TIMEOUT 30000
|
||||
|
||||
/**
|
||||
* The retransmission algorithm uses a multiple sequences.
|
||||
* Each sequence contains multiple retransmits. Those retransmits
|
||||
* are sent using a exponential backoff algorithm. The sequences
|
||||
* are retried with linear timings:
|
||||
*
|
||||
* <------sequence---------><------sequence---------><------sequence--------->
|
||||
*
|
||||
* T-R---R-----R---------R--R-R---R-----R---------R--R-R---R-----R---------R--X
|
||||
*
|
||||
* T = first transmit
|
||||
* R = retransmit
|
||||
* X = giving up, peer is dead
|
||||
*
|
||||
* if (retransmit >= TRIES * sequences)
|
||||
* => abort
|
||||
* TIMEOUT * (BASE ** (try % TRIES))
|
||||
*
|
||||
* Using an initial TIMEOUT of 4s, a BASE of 1.8, 5 TRIES
|
||||
* per sequnce and 3 sequences, this gives us:
|
||||
*
|
||||
* | relative | absolute
|
||||
* ---------------------------------------------------------
|
||||
* 4s * (1.8 ** (0 % 5)) = 4s 4s
|
||||
* 4s * (1.8 ** (1 % 5)) = 7s 11s
|
||||
* 4s * (1.8 ** (2 % 5)) = 13s 24s
|
||||
* 4s * (1.8 ** (3 % 5)) = 23s 47s
|
||||
* 4s * (1.8 ** (4 % 5)) = 42s 89s
|
||||
* 4s * (1.8 ** (5 % 5)) = 76s 165s
|
||||
* 4s * (1.8 ** (6 % 5)) = 4s 169s
|
||||
* 4s * (1.8 ** (7 % 5)) = 7s 176s
|
||||
* 4s * (1.8 ** (8 % 5)) = 13s 189s
|
||||
* 4s * (1.8 ** (9 % 5)) = 23s 212s
|
||||
* 4s * (1.8 ** (10 % 5)) = 42s 254s
|
||||
* 4s * (1.8 ** (11 % 5)) = 76s 330s
|
||||
* 4s * (1.8 ** (12 % 5)) = 4s 334
|
||||
* 4s * (1.8 ** (13 % 5)) = 7s 341s
|
||||
* 4s * (1.8 ** (14 % 5)) = 13s 354s
|
||||
* 4s * (1.8 ** (15 % 5)) = 23s 377s
|
||||
* 4s * (1.8 ** (16 % 5)) = 42s 419s
|
||||
* 4s * (1.8 ** (17 % 5)) = 76s 495s
|
||||
*
|
||||
* If the configuration uses 1 sequence, the peer is considered dead
|
||||
* after 2min 45s when no reply comes in. If it uses 3 sequences, after
|
||||
* 8min 15s the DPD action is executed...
|
||||
*/
|
||||
|
||||
/**
|
||||
* First retransmit timeout in milliseconds.
|
||||
* Timeout value is increasing in each retransmit round.
|
||||
*/
|
||||
#define RETRANSMIT_TIMEOUT 6000
|
||||
#define RETRANSMIT_TIMEOUT 4000
|
||||
|
||||
/**
|
||||
* Base which is raised to the power of the retransmission count.
|
||||
*/
|
||||
#define RETRANSMIT_BASE 1.5
|
||||
#define RETRANSMIT_BASE 1.8
|
||||
|
||||
/**
|
||||
* Max retransmit count.
|
||||
* 0 for infinite. The max time a half open IKE_SA is alive is set by
|
||||
* RETRANSMIT_TIMEOUT.
|
||||
* Number of retransmits done in a retransmit sequence
|
||||
*/
|
||||
#define MAX_RETRANSMIT_COUNT 6
|
||||
#define RETRANSMIT_TRIES 5
|
||||
|
||||
/**
|
||||
* Keepalive interval in seconds.
|
||||
*/
|
||||
#define KEEPALIVE_INTERVAL 20
|
||||
|
||||
/**
|
||||
* DPD interval in seconds.
|
||||
*/
|
||||
#define DPD_INTERVAL 60
|
||||
|
||||
|
||||
typedef struct private_configuration_t private_configuration_t;
|
||||
|
||||
@@ -79,13 +118,18 @@ struct private_configuration_t {
|
||||
/**
|
||||
* Implementation of configuration_t.get_retransmit_timeout.
|
||||
*/
|
||||
static u_int32_t get_retransmit_timeout (private_configuration_t *this, u_int32_t retransmit_count)
|
||||
static u_int32_t get_retransmit_timeout (private_configuration_t *this,
|
||||
u_int32_t retransmit_count,
|
||||
u_int32_t max_sequences)
|
||||
{
|
||||
if (retransmit_count > MAX_RETRANSMIT_COUNT && MAX_RETRANSMIT_COUNT != 0)
|
||||
if (max_sequences != 0 &&
|
||||
retransmit_count >= RETRANSMIT_TRIES * max_sequences)
|
||||
{
|
||||
/* give up */
|
||||
return 0;
|
||||
}
|
||||
return (u_int32_t)(RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
|
||||
return (u_int32_t)(RETRANSMIT_TIMEOUT *
|
||||
pow(RETRANSMIT_BASE, retransmit_count % RETRANSMIT_TRIES));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,14 +148,6 @@ static u_int32_t get_keepalive_interval (private_configuration_t *this)
|
||||
return KEEPALIVE_INTERVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of configuration_t.get_dpd_interval.
|
||||
*/
|
||||
static u_int32_t get_dpd_interval (private_configuration_t *this)
|
||||
{
|
||||
return DPD_INTERVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of configuration_t.destroy.
|
||||
*/
|
||||
@@ -129,10 +165,9 @@ configuration_t *configuration_create()
|
||||
|
||||
/* public functions */
|
||||
this->public.destroy = (void(*)(configuration_t*))destroy;
|
||||
this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t *, u_int32_t retransmit_count))get_retransmit_timeout;
|
||||
this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t *)) get_half_open_ike_sa_timeout;
|
||||
this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t *)) get_keepalive_interval;
|
||||
this->public.get_dpd_interval = (u_int32_t (*) (configuration_t *)) get_dpd_interval;
|
||||
this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t*,u_int32_t,u_int32_t))get_retransmit_timeout;
|
||||
this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t*)) get_half_open_ike_sa_timeout;
|
||||
this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t*)) get_keepalive_interval;
|
||||
|
||||
return (&this->public);
|
||||
}
|
||||
|
||||
@@ -36,34 +36,33 @@ typedef struct configuration_t configuration_t;
|
||||
*
|
||||
* @ingroup config
|
||||
*/
|
||||
struct configuration_t {
|
||||
struct configuration_t {
|
||||
|
||||
/**
|
||||
* @brief Returns the retransmit timeout.
|
||||
*
|
||||
* A return value of zero means the request should not retransmitted again.
|
||||
* The timeout values are managed by the configuration, so
|
||||
* another backoff algorithm may be implemented here.
|
||||
* A return value of zero means the request should not be retransmitted again.
|
||||
* The retransmission algorithm uses sequences of retransmits, in which
|
||||
* every sequence contains exponential delayed retransmits. These
|
||||
* sequences are compareable to the keyingtries mechanism used in pluto.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param retransmit_count number of times a message was retransmitted so far
|
||||
* @param retransmitted number of times a message was retransmitted so far
|
||||
* @param max_sequences maximum number of retransmission sequences to allow
|
||||
* @return time in milliseconds, when to schedule next retransmit
|
||||
*/
|
||||
u_int32_t (*get_retransmit_timeout) (configuration_t *this, u_int32_t retransmit_count);
|
||||
u_int32_t (*get_retransmit_timeout) (configuration_t *this,
|
||||
u_int32_t retransmitted,
|
||||
u_int32_t max_sequences);
|
||||
|
||||
/**
|
||||
* @brief Returns the timeout for an half open IKE_SA in ms.
|
||||
*
|
||||
* Half open means that the IKE_SA is still in one of the following states:
|
||||
* - INITIATOR_INIT
|
||||
* - RESPONDER_INIT
|
||||
* - IKE_SA_INIT_REQUESTED
|
||||
* - IKE_SA_INIT_RESPONDED
|
||||
* - IKE_AUTH_REQUESTED
|
||||
*
|
||||
*
|
||||
* Half open means that the IKE_SA is still on a not established state
|
||||
*
|
||||
* @param this calling object
|
||||
* @return timeout in milliseconds (ms)
|
||||
*/
|
||||
*/
|
||||
u_int32_t (*get_half_open_ike_sa_timeout) (configuration_t *this);
|
||||
|
||||
/**
|
||||
@@ -77,17 +76,6 @@ struct configuration_t {
|
||||
*/
|
||||
u_int32_t (*get_keepalive_interval) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Returns the DPD interval in ms.
|
||||
*
|
||||
* The DPD interval defines the time after which a
|
||||
* DPD request packet should be sent.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return interval in seconds
|
||||
*/
|
||||
u_int32_t (*get_dpd_interval) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroys a configuration_t object.
|
||||
*
|
||||
|
||||
@@ -105,6 +105,16 @@ struct private_connection_t {
|
||||
*/
|
||||
auth_method_t auth_method;
|
||||
|
||||
/**
|
||||
* Interval to send DPD liveness checks on inactivity
|
||||
*/
|
||||
u_int32_t dpd_delay;
|
||||
|
||||
/**
|
||||
* Number of retransmission sequences to send bevore giving up
|
||||
*/
|
||||
u_int32_t retrans_sequences;
|
||||
|
||||
/**
|
||||
* Supported proposals
|
||||
*/
|
||||
@@ -248,6 +258,22 @@ static auth_method_t get_auth_method(private_connection_t *this)
|
||||
return this->auth_method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of connection_t.get_dpd_delay.
|
||||
*/
|
||||
static u_int32_t get_dpd_delay(private_connection_t *this)
|
||||
{
|
||||
return this->dpd_delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of connection_t.get_retrans_seq.
|
||||
*/
|
||||
static u_int32_t get_retrans_seq(private_connection_t *this)
|
||||
{
|
||||
return this->retrans_sequences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of connection_t.get_dh_group.
|
||||
*/
|
||||
@@ -359,6 +385,8 @@ connection_t * connection_create(char *name, bool ikev2,
|
||||
cert_policy_t certreq_policy,
|
||||
host_t *my_host, host_t *other_host,
|
||||
auth_method_t auth_method,
|
||||
u_int32_t dpd_delay,
|
||||
u_int32_t retrans_sequences,
|
||||
u_int32_t hard_lifetime,
|
||||
u_int32_t soft_lifetime, u_int32_t jitter)
|
||||
{
|
||||
@@ -375,6 +403,8 @@ connection_t * connection_create(char *name, bool ikev2,
|
||||
this->public.select_proposal = (proposal_t*(*)(connection_t*,linked_list_t*))select_proposal;
|
||||
this->public.add_proposal = (void(*)(connection_t*, proposal_t*)) add_proposal;
|
||||
this->public.get_auth_method = (auth_method_t(*)(connection_t*)) get_auth_method;
|
||||
this->public.get_dpd_delay = (u_int32_t(*)(connection_t*)) get_dpd_delay;
|
||||
this->public.get_retrans_seq = (u_int32_t(*)(connection_t*)) get_retrans_seq;
|
||||
this->public.get_dh_group = (diffie_hellman_group_t(*)(connection_t*)) get_dh_group;
|
||||
this->public.check_dh_group = (bool(*)(connection_t*,diffie_hellman_group_t)) check_dh_group;
|
||||
this->public.get_soft_lifetime = (u_int32_t (*) (connection_t *))get_soft_lifetime;
|
||||
@@ -391,6 +421,8 @@ connection_t * connection_create(char *name, bool ikev2,
|
||||
this->my_host = my_host;
|
||||
this->other_host = other_host;
|
||||
this->auth_method = auth_method;
|
||||
this->dpd_delay = dpd_delay;
|
||||
this->retrans_sequences = retrans_sequences;
|
||||
this->hard_lifetime = hard_lifetime;
|
||||
this->soft_lifetime = soft_lifetime;
|
||||
this->jitter = jitter;
|
||||
|
||||
@@ -164,13 +164,32 @@ struct connection_t {
|
||||
proposal_t *(*select_proposal) (connection_t *this, linked_list_t *proposals);
|
||||
|
||||
/**
|
||||
* @brief Get the authentication method to use
|
||||
* @brief Get the authentication method to use.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return authentication method
|
||||
*/
|
||||
auth_method_t (*get_auth_method) (connection_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the DPD check interval.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return dpd_delay in seconds
|
||||
*/
|
||||
u_int32_t (*get_dpd_delay) (connection_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the max number of retransmission sequences.
|
||||
*
|
||||
* After this number of sequences, a not responding peer is considered
|
||||
* dead.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return max number of retransmission sequences
|
||||
*/
|
||||
u_int32_t (*get_retrans_seq) (connection_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the connection name.
|
||||
*
|
||||
@@ -281,9 +300,12 @@ struct connection_t {
|
||||
/**
|
||||
* @brief Creates a connection_t object.
|
||||
*
|
||||
* Supplied hosts become owned by connection, so
|
||||
* do not modify or destroy them after a call to
|
||||
* Supplied hosts become owned by connection, so
|
||||
* do not modify or destroy them after a call to
|
||||
* connection_create(). Name gets cloned internally.
|
||||
* The retrasmit sequence number says how fast we give up when the peer
|
||||
* does not respond. A high value may bridge-over temporary connection
|
||||
* problems, a small value can detect dead peers faster.
|
||||
*
|
||||
* @param name connection identifier
|
||||
* @param ikev2 TRUE if this is an IKEv2 connection
|
||||
@@ -292,6 +314,8 @@ struct connection_t {
|
||||
* @param my_host host_t representing local address
|
||||
* @param other_host host_t representing remote address
|
||||
* @param auth_method Authentication method to use for our(!) auth data
|
||||
* @param dpd_delay interval of DPD liveness checks
|
||||
* @param retrans_sequences number of retransmit sequences to use
|
||||
* @param hard_lifetime lifetime before deleting an IKE_SA
|
||||
* @param soft_lifetime lifetime before rekeying an IKE_SA
|
||||
* @param jitter range of randomization time
|
||||
@@ -302,7 +326,9 @@ struct connection_t {
|
||||
connection_t * connection_create(char *name, bool ikev2,
|
||||
cert_policy_t cert_pol, cert_policy_t req_pol,
|
||||
host_t *my_host, host_t *other_host,
|
||||
auth_method_t auth_method, u_int32_t hard_lifetime,
|
||||
u_int32_t soft_lifetime, u_int32_t jitter);
|
||||
auth_method_t auth_method,
|
||||
u_int32_t dpd_delay, u_int32_t retrans_sequences,
|
||||
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
|
||||
u_int32_t jitter);
|
||||
|
||||
#endif /* CONNECTION_H_ */
|
||||
|
||||
@@ -109,6 +109,11 @@ struct private_policy_t {
|
||||
*/
|
||||
u_int32_t jitter;
|
||||
|
||||
/**
|
||||
* Should the SA get ROUTED when peer detected as dead?
|
||||
*/
|
||||
bool dpd_route;
|
||||
|
||||
/**
|
||||
* logger
|
||||
*/
|
||||
@@ -441,7 +446,7 @@ static void destroy(private_policy_t *this)
|
||||
*/
|
||||
policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
|
||||
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
|
||||
u_int32_t jitter, char *updown)
|
||||
u_int32_t jitter, char *updown, bool dpd_route)
|
||||
{
|
||||
private_policy_t *this = malloc_thing(private_policy_t);
|
||||
|
||||
@@ -473,6 +478,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
|
||||
this->soft_lifetime = soft_lifetime;
|
||||
this->jitter = jitter;
|
||||
this->updown = (updown == NULL) ? NULL : strdup(updown);
|
||||
this->dpd_route = dpd_route;
|
||||
|
||||
/* initialize private members*/
|
||||
this->refcount = 1;
|
||||
|
||||
@@ -264,6 +264,7 @@ struct policy_t {
|
||||
* @param soft_lifetime lifetime before rekeying an SA
|
||||
* @param jitter range of randomization time
|
||||
* @param updown updown script to execute on up/down event
|
||||
* @param dpd_route should the connection go to routed state if DPD detected?
|
||||
* @return policy_t object
|
||||
*
|
||||
* @ingroup config
|
||||
@@ -271,6 +272,6 @@ struct policy_t {
|
||||
policy_t *policy_create(char *name,
|
||||
identification_t *my_id, identification_t *other_id,
|
||||
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
|
||||
u_int32_t jitter, char *updown);
|
||||
u_int32_t jitter, char *updown, bool dpd_route);
|
||||
|
||||
#endif /* POLICY_H_ */
|
||||
|
||||
@@ -464,24 +464,16 @@ static u_int8_t get_protocol(private_traffic_selector_t *this)
|
||||
*/
|
||||
static void update_address_range(private_traffic_selector_t *this, host_t *host)
|
||||
{
|
||||
if (host->get_family(host) == AF_INET && this->type == TS_IPV4_ADDR_RANGE)
|
||||
if ((this->type == TS_IPV4_ADDR_RANGE && this->from4[0] == 0) ||
|
||||
(this->type == TS_IPV6_ADDR_RANGE && this->from6[0] == 0 &&
|
||||
this->from6[1] == 0 && this->from6[2] == 0 && this->from6[3] == 0))
|
||||
{
|
||||
if (this->from4[0] == 0)
|
||||
{
|
||||
chunk_t from = host->get_address(host);
|
||||
memcpy(this->from4, from.ptr, from.len);
|
||||
memcpy(this->to4, from.ptr, from.len);
|
||||
}
|
||||
}
|
||||
if (host->get_family(host) == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE)
|
||||
{
|
||||
if (this->from6[0] == 0 && this->from6[1] == 0 &&
|
||||
this->from6[2] == 0 && this->from6[3] == 0)
|
||||
{
|
||||
chunk_t from = host->get_address(host);
|
||||
memcpy(this->from6, from.ptr, from.len);
|
||||
memcpy(this->to6, from.ptr, from.len);
|
||||
}
|
||||
this->type = host->get_family(host) == AF_INET ?
|
||||
TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
|
||||
|
||||
chunk_t from = host->get_address(host);
|
||||
memcpy(this->from, from.ptr, from.len);
|
||||
memcpy(this->to, from.ptr, from.len);
|
||||
}
|
||||
update_string(this);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user