2005-12-04 19:05:52 +00:00
|
|
|
/*
|
2010-07-12 08:35:19 +00:00
|
|
|
* Copyright (C) 2006-2010 Tobias Brunner
|
2008-10-14 08:52:13 +00:00
|
|
|
* Copyright (C) 2005-2008 Martin Willi
|
2008-05-08 16:19:11 +00:00
|
|
|
* Copyright (C) 2006 Daniel Roethlisberger
|
2006-07-07 08:49:06 +00:00
|
|
|
* Copyright (C) 2005 Jan Hutter
|
2005-12-04 19:05:52 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2006-10-18 11:46:13 +00:00
|
|
|
#define _GNU_SOURCE
|
2006-04-26 12:28:02 +00:00
|
|
|
#include "child_sa.h"
|
2005-12-04 19:05:52 +00:00
|
|
|
|
2006-09-08 13:10:52 +00:00
|
|
|
#include <stdio.h>
|
2006-08-28 08:45:22 +00:00
|
|
|
#include <string.h>
|
2008-11-05 08:32:38 +00:00
|
|
|
#include <time.h>
|
2006-08-28 08:45:22 +00:00
|
|
|
|
2010-07-12 09:14:54 +00:00
|
|
|
#include <hydra.h>
|
2006-02-10 08:20:06 +00:00
|
|
|
#include <daemon.h>
|
|
|
|
|
2008-10-14 08:52:13 +00:00
|
|
|
ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
|
2006-10-18 11:46:13 +00:00
|
|
|
"CREATED",
|
|
|
|
"ROUTED",
|
2008-11-11 09:22:00 +00:00
|
|
|
"INSTALLING",
|
2006-10-18 11:46:13 +00:00
|
|
|
"INSTALLED",
|
2008-10-16 11:48:18 +00:00
|
|
|
"UPDATING",
|
2006-10-18 11:46:13 +00:00
|
|
|
"REKEYING",
|
|
|
|
"DELETING",
|
2008-10-14 08:52:13 +00:00
|
|
|
"DESTROYING",
|
2006-10-18 11:46:13 +00:00
|
|
|
);
|
2006-07-13 08:26:54 +00:00
|
|
|
|
2005-12-04 19:05:52 +00:00
|
|
|
typedef struct private_child_sa_t private_child_sa_t;
|
|
|
|
|
|
|
|
/**
|
2007-07-03 13:49:29 +00:00
|
|
|
* Private data of a child_sa_t object.
|
2005-12-04 19:05:52 +00:00
|
|
|
*/
|
|
|
|
struct private_child_sa_t {
|
|
|
|
/**
|
2005-12-07 08:13:22 +00:00
|
|
|
* Public interface of child_sa_t.
|
2005-12-04 19:05:52 +00:00
|
|
|
*/
|
|
|
|
child_sa_t public;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-29 16:06:16 +00:00
|
|
|
/**
|
|
|
|
* address of us
|
|
|
|
*/
|
|
|
|
host_t *my_addr;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-06-15 11:06:22 +00:00
|
|
|
/**
|
2008-10-29 16:06:16 +00:00
|
|
|
* address of remote
|
2006-06-15 11:06:22 +00:00
|
|
|
*/
|
2008-10-29 16:06:16 +00:00
|
|
|
host_t *other_addr;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-06-15 11:06:22 +00:00
|
|
|
/**
|
2008-10-29 16:06:16 +00:00
|
|
|
* our actually used SPI, 0 if unused
|
2006-06-15 11:06:22 +00:00
|
|
|
*/
|
2008-10-29 16:06:16 +00:00
|
|
|
u_int32_t my_spi;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-02-10 08:20:06 +00:00
|
|
|
/**
|
2008-10-29 16:06:16 +00:00
|
|
|
* others used SPI, 0 if unused
|
2006-02-10 08:20:06 +00:00
|
|
|
*/
|
2008-10-29 16:06:16 +00:00
|
|
|
u_int32_t other_spi;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-07-20 10:09:32 +00:00
|
|
|
/**
|
2008-10-29 16:06:16 +00:00
|
|
|
* our Compression Parameter Index (CPI) used, 0 if unused
|
2006-07-20 10:09:32 +00:00
|
|
|
*/
|
2008-10-29 16:06:16 +00:00
|
|
|
u_int16_t my_cpi;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-07-20 10:09:32 +00:00
|
|
|
/**
|
2008-10-29 16:06:16 +00:00
|
|
|
* others Compression Parameter Index (CPI) used, 0 if unused
|
2006-07-20 10:09:32 +00:00
|
|
|
*/
|
2008-10-29 16:06:16 +00:00
|
|
|
u_int16_t other_cpi;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-03-01 15:56:51 +00:00
|
|
|
/**
|
2008-10-29 16:06:16 +00:00
|
|
|
* List for local traffic selectors
|
2006-03-01 15:56:51 +00:00
|
|
|
*/
|
2008-10-29 16:06:16 +00:00
|
|
|
linked_list_t *my_ts;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-29 16:06:16 +00:00
|
|
|
/**
|
|
|
|
* List for remote traffic selectors
|
|
|
|
*/
|
|
|
|
linked_list_t *other_ts;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-07-20 14:57:49 +00:00
|
|
|
/**
|
2008-10-29 16:06:16 +00:00
|
|
|
* Protocol used to protect this SA, ESP|AH
|
2006-07-20 14:57:49 +00:00
|
|
|
*/
|
2008-10-29 16:06:16 +00:00
|
|
|
protocol_id_t protocol;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-03-26 10:06:45 +00:00
|
|
|
/**
|
2008-10-29 16:06:16 +00:00
|
|
|
* reqid used for this child_sa
|
2008-03-26 10:06:45 +00:00
|
|
|
*/
|
2008-10-29 16:06:16 +00:00
|
|
|
u_int32_t reqid;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2010-07-02 21:45:57 +00:00
|
|
|
/**
|
|
|
|
* inbound mark used for this child_sa
|
|
|
|
*/
|
|
|
|
mark_t mark_in;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* outbound mark used for this child_sa
|
|
|
|
*/
|
|
|
|
mark_t mark_out;
|
|
|
|
|
2006-06-12 07:33:20 +00:00
|
|
|
/**
|
2008-10-24 08:02:35 +00:00
|
|
|
* absolute time when rekeying is scheduled
|
2006-06-12 07:33:20 +00:00
|
|
|
*/
|
2008-10-24 08:02:35 +00:00
|
|
|
time_t rekey_time;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2007-03-20 14:56:41 +00:00
|
|
|
/**
|
2008-10-24 08:02:35 +00:00
|
|
|
* absolute time when the SA expires
|
2007-03-20 14:56:41 +00:00
|
|
|
*/
|
2008-10-24 08:02:35 +00:00
|
|
|
time_t expire_time;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-07-13 08:26:54 +00:00
|
|
|
/**
|
|
|
|
* state of the CHILD_SA
|
|
|
|
*/
|
|
|
|
child_sa_state_t state;
|
2006-09-25 05:58:45 +00:00
|
|
|
|
2006-09-08 06:12:02 +00:00
|
|
|
/**
|
2007-06-27 13:10:55 +00:00
|
|
|
* Specifies if UDP encapsulation is enabled (NAT traversal)
|
2006-09-08 06:12:02 +00:00
|
|
|
*/
|
2007-06-27 13:10:55 +00:00
|
|
|
bool encap;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-05-08 16:19:11 +00:00
|
|
|
/**
|
|
|
|
* Specifies the IPComp transform used (IPCOMP_NONE if disabled)
|
|
|
|
*/
|
|
|
|
ipcomp_transform_t ipcomp;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-12-21 14:35:17 +00:00
|
|
|
/**
|
|
|
|
* mode this SA uses, tunnel/transport
|
|
|
|
*/
|
2008-09-25 13:56:23 +00:00
|
|
|
ipsec_mode_t mode;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2010-06-02 09:40:38 +00:00
|
|
|
/**
|
|
|
|
* Action to enforce if peer closes the CHILD_SA
|
|
|
|
*/
|
|
|
|
action_t close_action;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to enforce if peer is considered dead
|
|
|
|
*/
|
|
|
|
action_t dpd_action;
|
|
|
|
|
2008-10-29 16:06:16 +00:00
|
|
|
/**
|
2009-09-04 13:02:11 +00:00
|
|
|
* selected proposal
|
|
|
|
*/
|
|
|
|
proposal_t *proposal;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2007-02-28 14:04:36 +00:00
|
|
|
/**
|
2007-04-10 06:01:03 +00:00
|
|
|
* config used to create this child
|
2007-02-28 14:04:36 +00:00
|
|
|
*/
|
2007-04-10 06:01:03 +00:00
|
|
|
child_cfg_t *config;
|
2009-07-30 21:19:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* time of last use in seconds (inbound)
|
|
|
|
*/
|
|
|
|
u_int32_t my_usetime;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* time of last use in seconds (outbound)
|
|
|
|
*/
|
|
|
|
u_int32_t other_usetime;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* last number of inbound bytes
|
|
|
|
*/
|
|
|
|
u_int64_t my_usebytes;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* last number of outbound bytes
|
|
|
|
*/
|
|
|
|
u_int64_t other_usebytes;
|
2005-12-04 19:05:52 +00:00
|
|
|
};
|
|
|
|
|
2010-07-12 08:35:19 +00:00
|
|
|
/**
|
|
|
|
* convert an IKEv2 specific protocol identifier to the IP protocol identifier.
|
|
|
|
*/
|
|
|
|
static inline u_int8_t proto_ike2ip(protocol_id_t protocol)
|
|
|
|
{
|
|
|
|
switch (protocol)
|
|
|
|
{
|
|
|
|
case PROTO_ESP:
|
|
|
|
return IPPROTO_ESP;
|
|
|
|
case PROTO_AH:
|
|
|
|
return IPPROTO_AH;
|
|
|
|
default:
|
|
|
|
return protocol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_name, char*,
|
|
|
|
private_child_sa_t *this)
|
2006-08-25 09:07:37 +00:00
|
|
|
{
|
2007-04-10 06:01:03 +00:00
|
|
|
return this->config->get_name(this->config);
|
2006-08-25 09:07:37 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_reqid, u_int32_t,
|
|
|
|
private_child_sa_t *this)
|
2006-05-31 14:23:15 +00:00
|
|
|
{
|
|
|
|
return this->reqid;
|
|
|
|
}
|
2008-11-19 15:31:27 +00:00
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_config, child_cfg_t*,
|
|
|
|
private_child_sa_t *this)
|
2008-11-19 15:31:27 +00:00
|
|
|
{
|
|
|
|
return this->config;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, set_state, void,
|
|
|
|
private_child_sa_t *this, child_sa_state_t state)
|
2008-11-19 15:31:27 +00:00
|
|
|
{
|
|
|
|
charon->bus->child_state_change(charon->bus, &this->public, state);
|
|
|
|
this->state = state;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_state, child_sa_state_t,
|
|
|
|
private_child_sa_t *this)
|
2008-11-19 15:31:27 +00:00
|
|
|
{
|
|
|
|
return this->state;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_spi, u_int32_t,
|
|
|
|
private_child_sa_t *this, bool inbound)
|
2006-06-07 13:26:23 +00:00
|
|
|
{
|
2008-10-29 16:06:16 +00:00
|
|
|
return inbound ? this->my_spi : this->other_spi;
|
2006-06-07 13:26:23 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_cpi, u_int16_t,
|
|
|
|
private_child_sa_t *this, bool inbound)
|
2008-07-22 12:03:58 +00:00
|
|
|
{
|
2008-10-29 16:06:16 +00:00
|
|
|
return inbound ? this->my_cpi : this->other_cpi;
|
2008-07-22 12:03:58 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_protocol, protocol_id_t,
|
|
|
|
private_child_sa_t *this)
|
2006-06-07 13:26:23 +00:00
|
|
|
{
|
|
|
|
return this->protocol;
|
|
|
|
}
|
2006-05-31 14:23:15 +00:00
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, set_protocol, void,
|
|
|
|
private_child_sa_t *this, protocol_id_t protocol)
|
2008-11-19 15:31:27 +00:00
|
|
|
{
|
|
|
|
this->protocol = protocol;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_mode, ipsec_mode_t,
|
|
|
|
private_child_sa_t *this)
|
2008-10-29 16:06:16 +00:00
|
|
|
{
|
|
|
|
return this->mode;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, set_mode, void,
|
|
|
|
private_child_sa_t *this, ipsec_mode_t mode)
|
2008-11-19 15:31:27 +00:00
|
|
|
{
|
|
|
|
this->mode = mode;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, has_encap, bool,
|
|
|
|
private_child_sa_t *this)
|
2008-10-24 09:51:48 +00:00
|
|
|
{
|
|
|
|
return this->encap;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_ipcomp, ipcomp_transform_t,
|
|
|
|
private_child_sa_t *this)
|
2008-10-24 09:51:48 +00:00
|
|
|
{
|
|
|
|
return this->ipcomp;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, set_ipcomp, void,
|
|
|
|
private_child_sa_t *this, ipcomp_transform_t ipcomp)
|
2006-07-13 08:26:54 +00:00
|
|
|
{
|
2008-11-19 15:31:27 +00:00
|
|
|
this->ipcomp = ipcomp;
|
2006-07-13 08:26:54 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, set_close_action, void,
|
|
|
|
private_child_sa_t *this, action_t action)
|
2010-06-02 09:40:38 +00:00
|
|
|
{
|
|
|
|
this->close_action = action;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_close_action, action_t,
|
|
|
|
private_child_sa_t *this)
|
2010-06-02 09:40:38 +00:00
|
|
|
{
|
|
|
|
return this->close_action;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, set_dpd_action, void,
|
|
|
|
private_child_sa_t *this, action_t action)
|
2010-06-02 09:40:38 +00:00
|
|
|
{
|
|
|
|
this->dpd_action = action;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_dpd_action, action_t,
|
|
|
|
private_child_sa_t *this)
|
2010-06-02 09:40:38 +00:00
|
|
|
{
|
|
|
|
return this->dpd_action;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_proposal, proposal_t*,
|
|
|
|
private_child_sa_t *this)
|
2007-02-28 14:04:36 +00:00
|
|
|
{
|
2008-11-19 15:31:27 +00:00
|
|
|
return this->proposal;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, set_proposal, void,
|
|
|
|
private_child_sa_t *this, proposal_t *proposal)
|
2008-11-19 15:31:27 +00:00
|
|
|
{
|
|
|
|
this->proposal = proposal->clone(proposal);
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_traffic_selectors, linked_list_t*,
|
|
|
|
private_child_sa_t *this, bool local)
|
2008-11-19 15:31:27 +00:00
|
|
|
{
|
|
|
|
return local ? this->my_ts : this->other_ts;
|
2007-02-28 14:04:36 +00:00
|
|
|
}
|
|
|
|
|
2008-10-15 12:24:44 +00:00
|
|
|
typedef struct policy_enumerator_t policy_enumerator_t;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Private policy enumerator
|
|
|
|
*/
|
|
|
|
struct policy_enumerator_t {
|
|
|
|
/** implements enumerator_t */
|
|
|
|
enumerator_t public;
|
|
|
|
/** enumerator over own TS */
|
|
|
|
enumerator_t *mine;
|
|
|
|
/** enumerator over others TS */
|
|
|
|
enumerator_t *other;
|
|
|
|
/** list of others TS, to recreate enumerator */
|
|
|
|
linked_list_t *list;
|
2008-10-21 10:57:40 +00:00
|
|
|
/** currently enumerating TS for "me" side */
|
|
|
|
traffic_selector_t *ts;
|
2008-10-15 12:24:44 +00:00
|
|
|
};
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(enumerator_t, policy_enumerate, bool,
|
|
|
|
policy_enumerator_t *this, traffic_selector_t **my_out,
|
|
|
|
traffic_selector_t **other_out)
|
2008-10-15 12:24:44 +00:00
|
|
|
{
|
2008-10-21 10:57:40 +00:00
|
|
|
traffic_selector_t *other_ts;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-21 10:57:40 +00:00
|
|
|
while (this->ts || this->mine->enumerate(this->mine, &this->ts))
|
2008-10-15 12:24:44 +00:00
|
|
|
{
|
2008-10-21 10:57:40 +00:00
|
|
|
if (!this->other->enumerate(this->other, &other_ts))
|
|
|
|
{ /* end of others list, restart with new of mine */
|
|
|
|
this->other->destroy(this->other);
|
|
|
|
this->other = this->list->create_enumerator(this->list);
|
|
|
|
this->ts = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (this->ts->get_type(this->ts) != other_ts->get_type(other_ts))
|
|
|
|
{ /* family mismatch */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (this->ts->get_protocol(this->ts) &&
|
|
|
|
other_ts->get_protocol(other_ts) &&
|
|
|
|
this->ts->get_protocol(this->ts) != other_ts->get_protocol(other_ts))
|
|
|
|
{ /* protocol mismatch */
|
|
|
|
continue;
|
2008-10-15 12:24:44 +00:00
|
|
|
}
|
2008-10-21 10:57:40 +00:00
|
|
|
*my_out = this->ts;
|
|
|
|
*other_out = other_ts;
|
|
|
|
return TRUE;
|
2008-10-15 12:24:44 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(enumerator_t, policy_destroy, void,
|
|
|
|
policy_enumerator_t *this)
|
2008-10-15 12:24:44 +00:00
|
|
|
{
|
|
|
|
this->mine->destroy(this->mine);
|
|
|
|
this->other->destroy(this->other);
|
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, create_policy_enumerator, enumerator_t*,
|
|
|
|
private_child_sa_t *this)
|
2008-10-15 12:24:44 +00:00
|
|
|
{
|
2010-07-12 07:38:39 +00:00
|
|
|
policy_enumerator_t *e;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
INIT(e,
|
|
|
|
.public = {
|
|
|
|
.enumerate = (void*)_policy_enumerate,
|
|
|
|
.destroy = _policy_destroy,
|
|
|
|
},
|
|
|
|
.mine = this->my_ts->create_enumerator(this->my_ts),
|
|
|
|
.other = this->other_ts->create_enumerator(this->other_ts),
|
|
|
|
.list = this->other_ts,
|
|
|
|
.ts = NULL,
|
|
|
|
);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-15 12:24:44 +00:00
|
|
|
return &e->public;
|
|
|
|
}
|
|
|
|
|
2009-08-06 13:14:54 +00:00
|
|
|
/**
|
|
|
|
* update the cached usebytes
|
|
|
|
* returns SUCCESS if the usebytes have changed, FAILED if not or no SPIs
|
|
|
|
* are available, and NOT_SUPPORTED if the kernel interface does not support
|
2009-08-07 03:59:09 +00:00
|
|
|
* querying the usebytes.
|
2009-08-06 13:14:54 +00:00
|
|
|
*/
|
2009-08-06 14:46:02 +00:00
|
|
|
static status_t update_usebytes(private_child_sa_t *this, bool inbound)
|
2009-08-06 13:14:54 +00:00
|
|
|
{
|
|
|
|
status_t status = FAILED;
|
|
|
|
u_int64_t bytes;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-06 13:14:54 +00:00
|
|
|
if (inbound)
|
|
|
|
{
|
|
|
|
if (this->my_spi)
|
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
status = hydra->kernel_interface->query_sa(hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
this->other_addr, this->my_addr, this->my_spi,
|
|
|
|
proto_ike2ip(this->protocol), this->mark_in,
|
|
|
|
&bytes);
|
2009-08-06 13:14:54 +00:00
|
|
|
if (status == SUCCESS)
|
|
|
|
{
|
|
|
|
if (bytes > this->my_usebytes)
|
|
|
|
{
|
|
|
|
this->my_usebytes = bytes;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (this->other_spi)
|
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
status = hydra->kernel_interface->query_sa(hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
this->my_addr, this->other_addr, this->other_spi,
|
|
|
|
proto_ike2ip(this->protocol), this->mark_out,
|
|
|
|
&bytes);
|
2009-08-06 13:14:54 +00:00
|
|
|
if (status == SUCCESS)
|
|
|
|
{
|
|
|
|
if (bytes > this->other_usebytes)
|
|
|
|
{
|
|
|
|
this->other_usebytes = bytes;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2007-04-11 12:14:51 +00:00
|
|
|
/**
|
2009-08-06 14:46:02 +00:00
|
|
|
* updates the cached usetime
|
2007-04-11 12:14:51 +00:00
|
|
|
*/
|
2009-08-06 14:46:02 +00:00
|
|
|
static void update_usetime(private_child_sa_t *this, bool inbound)
|
2007-04-11 12:14:51 +00:00
|
|
|
{
|
2008-10-15 12:24:44 +00:00
|
|
|
enumerator_t *enumerator;
|
2008-10-24 08:02:35 +00:00
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
|
|
|
u_int32_t last_use = 0;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-15 12:24:44 +00:00
|
|
|
enumerator = create_policy_enumerator(this);
|
|
|
|
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
|
2007-04-11 12:14:51 +00:00
|
|
|
{
|
2008-10-24 08:02:35 +00:00
|
|
|
u_int32_t in, out, fwd;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-06 13:14:54 +00:00
|
|
|
if (inbound)
|
2007-04-11 12:14:51 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
if (hydra->kernel_interface->query_policy(hydra->kernel_interface,
|
2010-07-02 21:45:57 +00:00
|
|
|
other_ts, my_ts, POLICY_IN, this->mark_in, &in) == SUCCESS)
|
2008-10-24 08:02:35 +00:00
|
|
|
{
|
|
|
|
last_use = max(last_use, in);
|
|
|
|
}
|
2008-11-12 16:47:19 +00:00
|
|
|
if (this->mode != MODE_TRANSPORT)
|
2008-10-24 08:02:35 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
if (hydra->kernel_interface->query_policy(hydra->kernel_interface,
|
2010-07-02 21:45:57 +00:00
|
|
|
other_ts, my_ts, POLICY_FWD, this->mark_in, &fwd) == SUCCESS)
|
2008-11-11 06:37:37 +00:00
|
|
|
{
|
|
|
|
last_use = max(last_use, fwd);
|
|
|
|
}
|
2008-10-24 08:02:35 +00:00
|
|
|
}
|
2007-04-11 12:14:51 +00:00
|
|
|
}
|
2008-10-24 08:02:35 +00:00
|
|
|
else
|
2007-04-11 12:14:51 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
if (hydra->kernel_interface->query_policy(hydra->kernel_interface,
|
2010-07-02 21:45:57 +00:00
|
|
|
my_ts, other_ts, POLICY_OUT, this->mark_out, &out) == SUCCESS)
|
2008-10-24 08:02:35 +00:00
|
|
|
{
|
|
|
|
last_use = max(last_use, out);
|
|
|
|
}
|
2007-04-11 12:14:51 +00:00
|
|
|
}
|
|
|
|
}
|
2008-10-15 12:24:44 +00:00
|
|
|
enumerator->destroy(enumerator);
|
2009-08-07 03:59:09 +00:00
|
|
|
|
|
|
|
if (last_use == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2009-07-30 21:19:42 +00:00
|
|
|
if (inbound)
|
|
|
|
{
|
|
|
|
this->my_usetime = last_use;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->other_usetime = last_use;
|
|
|
|
}
|
2008-10-24 08:02:35 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_usestats, void,
|
|
|
|
private_child_sa_t *this, bool inbound, time_t *time, u_int64_t *bytes)
|
2009-07-30 19:33:19 +00:00
|
|
|
{
|
2009-08-06 14:46:02 +00:00
|
|
|
if (update_usebytes(this, inbound) != FAILED)
|
2009-08-07 03:59:09 +00:00
|
|
|
{
|
|
|
|
/* there was traffic since last update or the kernel interface
|
|
|
|
* does not support querying the number of usebytes.
|
|
|
|
*/
|
2009-08-06 14:46:02 +00:00
|
|
|
update_usetime(this, inbound);
|
|
|
|
}
|
|
|
|
if (time)
|
|
|
|
{
|
|
|
|
*time = inbound ? this->my_usetime : this->other_usetime;
|
|
|
|
}
|
|
|
|
if (bytes)
|
|
|
|
{
|
|
|
|
*bytes = inbound ? this->my_usebytes : this->other_usebytes;
|
|
|
|
}
|
2009-07-30 19:33:19 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_lifetime, time_t,
|
|
|
|
private_child_sa_t *this, bool hard)
|
2008-10-24 08:02:35 +00:00
|
|
|
{
|
2008-10-29 16:06:16 +00:00
|
|
|
return hard ? this->expire_time : this->rekey_time;
|
2007-04-11 12:14:51 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, alloc_spi, u_int32_t,
|
|
|
|
private_child_sa_t *this, protocol_id_t protocol)
|
2006-06-22 06:36:28 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
if (hydra->kernel_interface->get_spi(hydra->kernel_interface,
|
|
|
|
this->other_addr, this->my_addr,
|
|
|
|
proto_ike2ip(protocol), this->reqid,
|
|
|
|
&this->my_spi) == SUCCESS)
|
2009-05-14 08:28:18 +00:00
|
|
|
{
|
|
|
|
return this->my_spi;
|
2006-06-22 06:36:28 +00:00
|
|
|
}
|
2008-11-19 15:31:27 +00:00
|
|
|
return 0;
|
2006-06-22 06:36:28 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, alloc_cpi, u_int16_t,
|
|
|
|
private_child_sa_t *this)
|
2005-12-04 19:05:52 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
if (hydra->kernel_interface->get_cpi(hydra->kernel_interface,
|
|
|
|
this->other_addr, this->my_addr,
|
|
|
|
this->reqid, &this->my_cpi) == SUCCESS)
|
2006-02-16 09:55:07 +00:00
|
|
|
{
|
2008-11-19 15:31:27 +00:00
|
|
|
return this->my_cpi;
|
2006-02-16 09:55:07 +00:00
|
|
|
}
|
2008-11-19 15:31:27 +00:00
|
|
|
return 0;
|
2005-12-04 19:05:52 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, install, status_t,
|
|
|
|
private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi,
|
|
|
|
u_int16_t cpi, bool inbound, linked_list_t *my_ts,
|
|
|
|
linked_list_t *other_ts)
|
2005-12-04 19:05:52 +00:00
|
|
|
{
|
2008-10-29 16:06:16 +00:00
|
|
|
u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
|
2009-12-17 09:50:37 +00:00
|
|
|
traffic_selector_t *src_ts = NULL, *dst_ts = NULL;
|
2009-08-27 09:45:36 +00:00
|
|
|
time_t now;
|
|
|
|
lifetime_cfg_t *lifetime;
|
2010-11-30 16:17:30 +00:00
|
|
|
u_int32_t tfc = 0;
|
2008-10-14 15:17:44 +00:00
|
|
|
host_t *src, *dst;
|
2006-02-16 09:55:07 +00:00
|
|
|
status_t status;
|
2008-11-19 15:31:27 +00:00
|
|
|
bool update = FALSE;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-29 16:06:16 +00:00
|
|
|
/* now we have to decide which spi to use. Use self allocated, if "in",
|
|
|
|
* or the one in the proposal, if not "in" (others). Additionally,
|
2006-06-15 11:06:22 +00:00
|
|
|
* source and dest host switch depending on the role */
|
2008-11-19 15:31:27 +00:00
|
|
|
if (inbound)
|
2006-02-10 08:20:06 +00:00
|
|
|
{
|
2008-10-29 16:06:16 +00:00
|
|
|
dst = this->my_addr;
|
|
|
|
src = this->other_addr;
|
2008-11-19 15:31:27 +00:00
|
|
|
if (this->my_spi == spi)
|
|
|
|
{ /* alloc_spi has been called, do an SA update */
|
|
|
|
update = TRUE;
|
|
|
|
}
|
|
|
|
this->my_spi = spi;
|
|
|
|
this->my_cpi = cpi;
|
2006-02-10 08:20:06 +00:00
|
|
|
}
|
2006-06-07 13:26:23 +00:00
|
|
|
else
|
|
|
|
{
|
2008-10-29 16:06:16 +00:00
|
|
|
src = this->my_addr;
|
|
|
|
dst = this->other_addr;
|
2008-11-19 15:31:27 +00:00
|
|
|
this->other_spi = spi;
|
|
|
|
this->other_cpi = cpi;
|
2010-12-08 12:41:04 +00:00
|
|
|
|
|
|
|
tfc = this->config->get_tfc(this->config);
|
2006-06-07 13:26:23 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-19 15:31:27 +00:00
|
|
|
DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
|
2006-10-18 11:46:13 +00:00
|
|
|
protocol_id_names, this->protocol);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-06-09 07:31:30 +00:00
|
|
|
/* send SA down to the kernel */
|
2006-10-26 09:46:56 +00:00
|
|
|
DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-19 15:31:27 +00:00
|
|
|
this->proposal->get_algorithm(this->proposal, ENCRYPTION_ALGORITHM,
|
|
|
|
&enc_alg, &size);
|
|
|
|
this->proposal->get_algorithm(this->proposal, INTEGRITY_ALGORITHM,
|
|
|
|
&int_alg, &size);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-27 09:45:36 +00:00
|
|
|
lifetime = this->config->get_lifetime(this->config);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-31 15:59:00 +00:00
|
|
|
now = time_monotonic(NULL);
|
2009-08-28 15:04:35 +00:00
|
|
|
if (lifetime->time.rekey)
|
2009-05-12 08:55:13 +00:00
|
|
|
{
|
2009-08-28 15:04:35 +00:00
|
|
|
this->rekey_time = now + lifetime->time.rekey;
|
2009-05-12 08:55:13 +00:00
|
|
|
}
|
2009-08-28 15:04:35 +00:00
|
|
|
if (lifetime->time.life)
|
2009-05-12 08:55:13 +00:00
|
|
|
{
|
2009-08-28 15:04:35 +00:00
|
|
|
this->expire_time = now + lifetime->time.life;
|
2009-08-27 09:45:36 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-28 15:04:35 +00:00
|
|
|
if (!lifetime->time.jitter && !inbound)
|
2009-08-27 09:45:36 +00:00
|
|
|
{ /* avoid triggering multiple rekey events */
|
2009-08-28 15:04:35 +00:00
|
|
|
lifetime->time.rekey = 0;
|
2009-05-12 08:55:13 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2010-12-13 14:28:40 +00:00
|
|
|
if (this->mode == MODE_BEET || this->mode == MODE_TRANSPORT)
|
2009-12-17 09:50:37 +00:00
|
|
|
{
|
|
|
|
/* BEET requires the bound address from the traffic selectors.
|
|
|
|
* TODO: We add just the first traffic selector for now, as the
|
|
|
|
* kernel accepts a single TS per SA only */
|
|
|
|
if (inbound)
|
|
|
|
{
|
|
|
|
my_ts->get_first(my_ts, (void**)&dst_ts);
|
|
|
|
other_ts->get_first(other_ts, (void**)&src_ts);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
my_ts->get_first(my_ts, (void**)&src_ts);
|
|
|
|
other_ts->get_first(other_ts, (void**)&dst_ts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-12 09:14:54 +00:00
|
|
|
status = hydra->kernel_interface->add_sa(hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
src, dst, spi, proto_ike2ip(this->protocol), this->reqid,
|
2010-11-30 16:17:30 +00:00
|
|
|
inbound ? this->mark_in : this->mark_out, tfc,
|
2010-07-02 21:45:57 +00:00
|
|
|
lifetime, enc_alg, encr, int_alg, integ, this->mode,
|
|
|
|
this->ipcomp, cpi, this->encap, update, src_ts, dst_ts);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-27 09:45:36 +00:00
|
|
|
free(lifetime);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-06-07 13:26:23 +00:00
|
|
|
return status;
|
2006-02-16 09:55:07 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, add_policies, status_t,
|
|
|
|
private_child_sa_t *this, linked_list_t *my_ts_list,
|
|
|
|
linked_list_t *other_ts_list)
|
2006-02-22 16:14:40 +00:00
|
|
|
{
|
2008-10-15 12:24:44 +00:00
|
|
|
enumerator_t *enumerator;
|
2006-03-01 15:56:51 +00:00
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
2008-10-15 12:24:44 +00:00
|
|
|
status_t status = SUCCESS;
|
2008-11-11 09:22:00 +00:00
|
|
|
bool routed = (this->state == CHILD_CREATED);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-15 12:24:44 +00:00
|
|
|
/* apply traffic selectors */
|
|
|
|
enumerator = my_ts_list->create_enumerator(my_ts_list);
|
|
|
|
while (enumerator->enumerate(enumerator, &my_ts))
|
2006-02-22 16:14:40 +00:00
|
|
|
{
|
2008-10-15 12:24:44 +00:00
|
|
|
this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts));
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
|
|
|
enumerator = other_ts_list->create_enumerator(other_ts_list);
|
|
|
|
while (enumerator->enumerate(enumerator, &other_ts))
|
|
|
|
{
|
|
|
|
this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts));
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
if (this->config->install_policy(this->config))
|
2008-10-15 12:24:44 +00:00
|
|
|
{
|
2010-08-03 09:50:56 +00:00
|
|
|
ipsec_sa_cfg_t my_sa = {
|
|
|
|
.mode = this->mode,
|
|
|
|
.reqid = this->reqid,
|
|
|
|
.ipcomp = {
|
|
|
|
.transform = this->ipcomp,
|
|
|
|
},
|
|
|
|
}, other_sa = my_sa;
|
|
|
|
|
|
|
|
my_sa.ipcomp.cpi = this->my_cpi;
|
|
|
|
other_sa.ipcomp.cpi = this->other_cpi;
|
|
|
|
|
2010-07-19 09:25:47 +00:00
|
|
|
if (this->protocol == PROTO_ESP)
|
|
|
|
{
|
2010-08-03 09:50:56 +00:00
|
|
|
my_sa.esp.use = TRUE;
|
|
|
|
my_sa.esp.spi = this->my_spi;
|
|
|
|
other_sa.esp.use = TRUE;
|
|
|
|
other_sa.esp.spi = this->other_spi;
|
2010-07-19 09:25:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-08-03 09:50:56 +00:00
|
|
|
my_sa.ah.use = TRUE;
|
|
|
|
my_sa.ah.spi = this->my_spi;
|
|
|
|
other_sa.ah.use = TRUE;
|
|
|
|
other_sa.ah.spi = this->other_spi;
|
2010-07-19 09:25:47 +00:00
|
|
|
}
|
2010-08-03 09:50:56 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
/* enumerate pairs of traffic selectors */
|
|
|
|
enumerator = create_policy_enumerator(this);
|
|
|
|
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
|
|
|
|
{
|
|
|
|
/* install 3 policies: out, in and forward */
|
2010-07-19 09:25:47 +00:00
|
|
|
status |= hydra->kernel_interface->add_policy(
|
|
|
|
hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
this->my_addr, this->other_addr, my_ts, other_ts,
|
2010-08-03 09:50:56 +00:00
|
|
|
POLICY_OUT, POLICY_IPSEC, &other_sa,
|
|
|
|
this->mark_out, routed);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2010-07-19 09:25:47 +00:00
|
|
|
status |= hydra->kernel_interface->add_policy(
|
|
|
|
hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
this->other_addr, this->my_addr, other_ts, my_ts,
|
2010-08-03 09:50:56 +00:00
|
|
|
POLICY_IN, POLICY_IPSEC, &my_sa,
|
|
|
|
this->mark_in, routed);
|
2008-11-19 15:31:27 +00:00
|
|
|
if (this->mode != MODE_TRANSPORT)
|
2008-11-11 06:37:37 +00:00
|
|
|
{
|
2010-07-19 09:25:47 +00:00
|
|
|
status |= hydra->kernel_interface->add_policy(
|
|
|
|
hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
this->other_addr, this->my_addr, other_ts, my_ts,
|
2010-08-03 09:50:56 +00:00
|
|
|
POLICY_FWD, POLICY_IPSEC, &my_sa,
|
|
|
|
this->mark_in, routed);
|
2008-11-11 06:37:37 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
if (status != SUCCESS)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2006-03-01 15:56:51 +00:00
|
|
|
}
|
2008-11-11 06:37:37 +00:00
|
|
|
enumerator->destroy(enumerator);
|
2006-03-01 15:56:51 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-19 15:31:27 +00:00
|
|
|
if (status == SUCCESS && this->state == CHILD_CREATED)
|
|
|
|
{ /* switch to routed state if no SAD entry set up */
|
|
|
|
set_state(this, CHILD_ROUTED);
|
2006-07-21 13:31:53 +00:00
|
|
|
}
|
2008-10-15 12:24:44 +00:00
|
|
|
return status;
|
2006-02-16 09:55:07 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, update, status_t,
|
|
|
|
private_child_sa_t *this, host_t *me, host_t *other, host_t *vip,
|
|
|
|
bool encap)
|
2006-06-22 06:36:28 +00:00
|
|
|
{
|
2008-10-16 11:48:18 +00:00
|
|
|
child_sa_state_t old;
|
2008-11-17 00:01:34 +00:00
|
|
|
bool transport_proxy_mode;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2007-06-26 13:04:13 +00:00
|
|
|
/* anything changed at all? */
|
2009-08-06 13:14:54 +00:00
|
|
|
if (me->equals(me, this->my_addr) &&
|
2008-10-29 16:06:16 +00:00
|
|
|
other->equals(other, this->other_addr) && this->encap == encap)
|
2006-06-22 06:36:28 +00:00
|
|
|
{
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-16 11:48:18 +00:00
|
|
|
old = this->state;
|
|
|
|
set_state(this, CHILD_UPDATING);
|
2008-11-17 00:01:34 +00:00
|
|
|
transport_proxy_mode = this->config->use_proxy_mode(this->config) &&
|
|
|
|
this->mode == MODE_TRANSPORT;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-17 00:01:34 +00:00
|
|
|
if (!transport_proxy_mode)
|
2008-11-11 09:22:00 +00:00
|
|
|
{
|
2008-11-16 21:19:58 +00:00
|
|
|
/* update our (initator) SA */
|
|
|
|
if (this->my_spi)
|
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
if (hydra->kernel_interface->update_sa(hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
this->my_spi, proto_ike2ip(this->protocol),
|
2008-11-16 21:19:58 +00:00
|
|
|
this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
|
|
|
|
this->other_addr, this->my_addr, other, me,
|
2010-07-02 21:45:57 +00:00
|
|
|
this->encap, encap, this->mark_in) == NOT_SUPPORTED)
|
2008-11-16 21:19:58 +00:00
|
|
|
{
|
|
|
|
return NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-16 21:19:58 +00:00
|
|
|
/* update his (responder) SA */
|
|
|
|
if (this->other_spi)
|
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
if (hydra->kernel_interface->update_sa(hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
this->other_spi, proto_ike2ip(this->protocol),
|
2009-09-04 12:58:05 +00:00
|
|
|
this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
|
2008-11-16 21:19:58 +00:00
|
|
|
this->my_addr, this->other_addr, me, other,
|
2010-07-02 21:45:57 +00:00
|
|
|
this->encap, encap, this->mark_out) == NOT_SUPPORTED)
|
2008-11-16 21:19:58 +00:00
|
|
|
{
|
|
|
|
return NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
2008-11-11 09:22:00 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
if (this->config->install_policy(this->config))
|
2006-06-22 06:36:28 +00:00
|
|
|
{
|
2010-08-03 09:50:56 +00:00
|
|
|
ipsec_sa_cfg_t my_sa = {
|
|
|
|
.mode = this->mode,
|
|
|
|
.reqid = this->reqid,
|
|
|
|
.ipcomp = {
|
|
|
|
.transform = this->ipcomp,
|
|
|
|
},
|
|
|
|
}, other_sa = my_sa;
|
|
|
|
|
|
|
|
my_sa.ipcomp.cpi = this->my_cpi;
|
|
|
|
other_sa.ipcomp.cpi = this->other_cpi;
|
|
|
|
|
2010-07-19 09:25:47 +00:00
|
|
|
if (this->protocol == PROTO_ESP)
|
|
|
|
{
|
2010-08-03 09:50:56 +00:00
|
|
|
my_sa.esp.use = TRUE;
|
|
|
|
my_sa.esp.spi = this->my_spi;
|
|
|
|
other_sa.esp.use = TRUE;
|
|
|
|
other_sa.esp.spi = this->other_spi;
|
2010-07-19 09:25:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-08-03 09:50:56 +00:00
|
|
|
my_sa.ah.use = TRUE;
|
|
|
|
my_sa.ah.spi = this->my_spi;
|
|
|
|
other_sa.ah.use = TRUE;
|
|
|
|
other_sa.ah.spi = this->other_spi;
|
2010-07-19 09:25:47 +00:00
|
|
|
}
|
2010-08-03 09:50:56 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
/* update policies */
|
|
|
|
if (!me->ip_equals(me, this->my_addr) ||
|
|
|
|
!other->ip_equals(other, this->other_addr))
|
2006-06-22 06:36:28 +00:00
|
|
|
{
|
2008-11-11 06:37:37 +00:00
|
|
|
enumerator_t *enumerator;
|
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
/* always use high priorities, as hosts getting updated are INSTALLED */
|
|
|
|
enumerator = create_policy_enumerator(this);
|
|
|
|
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
|
|
|
|
{
|
|
|
|
/* remove old policies first */
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_policy(hydra->kernel_interface,
|
2010-07-02 21:45:57 +00:00
|
|
|
my_ts, other_ts, POLICY_OUT, this->mark_out, FALSE);
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_policy(hydra->kernel_interface,
|
2010-07-02 21:45:57 +00:00
|
|
|
other_ts, my_ts, POLICY_IN, this->mark_in, FALSE);
|
2008-11-12 16:47:19 +00:00
|
|
|
if (this->mode != MODE_TRANSPORT)
|
2008-11-11 06:37:37 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_policy(hydra->kernel_interface,
|
2010-07-02 21:45:57 +00:00
|
|
|
other_ts, my_ts, POLICY_FWD, this->mark_in, FALSE);
|
2008-11-11 06:37:37 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
/* check whether we have to update a "dynamic" traffic selector */
|
|
|
|
if (!me->ip_equals(me, this->my_addr) &&
|
|
|
|
my_ts->is_host(my_ts, this->my_addr))
|
|
|
|
{
|
|
|
|
my_ts->set_address(my_ts, me);
|
|
|
|
}
|
|
|
|
if (!other->ip_equals(other, this->other_addr) &&
|
|
|
|
other_ts->is_host(other_ts, this->other_addr))
|
|
|
|
{
|
|
|
|
other_ts->set_address(other_ts, other);
|
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
/* we reinstall the virtual IP to handle interface roaming
|
|
|
|
* correctly */
|
|
|
|
if (vip)
|
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_ip(hydra->kernel_interface, vip);
|
|
|
|
hydra->kernel_interface->add_ip(hydra->kernel_interface, vip, me);
|
2008-11-11 06:37:37 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
/* reinstall updated policies */
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->add_policy(hydra->kernel_interface,
|
2010-07-19 16:38:29 +00:00
|
|
|
me, other, my_ts, other_ts, POLICY_OUT, POLICY_IPSEC,
|
2010-08-03 09:50:56 +00:00
|
|
|
&other_sa, this->mark_out, FALSE);
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->add_policy(hydra->kernel_interface,
|
2010-07-19 16:38:29 +00:00
|
|
|
other, me, other_ts, my_ts, POLICY_IN, POLICY_IPSEC,
|
2010-08-03 09:50:56 +00:00
|
|
|
&my_sa, this->mark_in, FALSE);
|
2008-11-12 16:47:19 +00:00
|
|
|
if (this->mode != MODE_TRANSPORT)
|
2008-11-11 06:37:37 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->add_policy(hydra->kernel_interface,
|
2010-07-19 16:38:29 +00:00
|
|
|
other, me, other_ts, my_ts, POLICY_FWD, POLICY_IPSEC,
|
2010-08-03 09:50:56 +00:00
|
|
|
&my_sa, this->mark_in, FALSE);
|
2008-11-11 06:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
2006-06-22 06:36:28 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-16 21:19:58 +00:00
|
|
|
|
2008-11-17 00:01:34 +00:00
|
|
|
if (!transport_proxy_mode)
|
|
|
|
{
|
|
|
|
/* apply hosts */
|
|
|
|
if (!me->equals(me, this->my_addr))
|
|
|
|
{
|
|
|
|
this->my_addr->destroy(this->my_addr);
|
|
|
|
this->my_addr = me->clone(me);
|
|
|
|
}
|
|
|
|
if (!other->equals(other, this->other_addr))
|
|
|
|
{
|
|
|
|
this->other_addr->destroy(this->other_addr);
|
|
|
|
this->other_addr = other->clone(other);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-11 09:22:00 +00:00
|
|
|
this->encap = encap;
|
2008-10-16 11:48:18 +00:00
|
|
|
set_state(this, old);
|
2008-11-16 21:19:58 +00:00
|
|
|
|
2006-06-22 06:36:28 +00:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, destroy, void,
|
|
|
|
private_child_sa_t *this)
|
2006-02-16 09:55:07 +00:00
|
|
|
{
|
2008-10-15 12:24:44 +00:00
|
|
|
enumerator_t *enumerator;
|
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
2008-11-11 09:22:00 +00:00
|
|
|
bool unrouted = (this->state == CHILD_ROUTED);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-14 08:52:13 +00:00
|
|
|
set_state(this, CHILD_DESTROYING);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-03-01 15:56:51 +00:00
|
|
|
/* delete SAs in the kernel, if they are set up */
|
2008-10-29 16:06:16 +00:00
|
|
|
if (this->my_spi)
|
2006-03-01 15:56:51 +00:00
|
|
|
{
|
2009-08-25 16:12:55 +00:00
|
|
|
/* if CHILD was not established, use PROTO_ESP used during alloc_spi().
|
|
|
|
* TODO: For AH support, we have to store protocol specific SPI.s */
|
|
|
|
if (this->protocol == PROTO_NONE)
|
|
|
|
{
|
|
|
|
this->protocol = PROTO_ESP;
|
|
|
|
}
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_sa(hydra->kernel_interface,
|
2009-04-30 11:37:54 +00:00
|
|
|
this->other_addr, this->my_addr, this->my_spi,
|
2010-07-12 08:35:19 +00:00
|
|
|
proto_ike2ip(this->protocol), this->my_cpi,
|
|
|
|
this->mark_in);
|
2006-06-15 11:06:22 +00:00
|
|
|
}
|
2008-10-29 16:06:16 +00:00
|
|
|
if (this->other_spi)
|
2006-06-15 11:06:22 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_sa(hydra->kernel_interface,
|
2009-04-30 11:37:54 +00:00
|
|
|
this->my_addr, this->other_addr, this->other_spi,
|
2010-07-12 08:35:19 +00:00
|
|
|
proto_ike2ip(this->protocol), this->other_cpi,
|
|
|
|
this->mark_out);
|
2008-05-08 16:19:11 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
if (this->config->install_policy(this->config))
|
2006-06-09 15:12:43 +00:00
|
|
|
{
|
2008-11-11 06:37:37 +00:00
|
|
|
/* delete all policies in the kernel */
|
|
|
|
enumerator = create_policy_enumerator(this);
|
|
|
|
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
|
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_policy(hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
my_ts, other_ts, POLICY_OUT, this->mark_out, unrouted);
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_policy(hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
other_ts, my_ts, POLICY_IN, this->mark_in, unrouted);
|
2008-11-12 16:47:19 +00:00
|
|
|
if (this->mode != MODE_TRANSPORT)
|
2008-11-11 06:37:37 +00:00
|
|
|
{
|
2010-07-12 09:14:54 +00:00
|
|
|
hydra->kernel_interface->del_policy(hydra->kernel_interface,
|
2010-07-12 08:35:19 +00:00
|
|
|
other_ts, my_ts, POLICY_FWD, this->mark_in, unrouted);
|
2008-11-11 06:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
2006-03-01 15:56:51 +00:00
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-15 12:24:44 +00:00
|
|
|
this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
|
|
|
|
this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
|
2008-10-29 16:06:16 +00:00
|
|
|
this->my_addr->destroy(this->my_addr);
|
|
|
|
this->other_addr->destroy(this->other_addr);
|
|
|
|
DESTROY_IF(this->proposal);
|
2007-04-10 06:01:03 +00:00
|
|
|
this->config->destroy(this->config);
|
2006-04-10 08:07:38 +00:00
|
|
|
free(this);
|
2006-02-16 09:55:07 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
/**
|
2006-02-16 09:55:07 +00:00
|
|
|
* Described in header.
|
|
|
|
*/
|
2007-02-28 14:04:36 +00:00
|
|
|
child_sa_t * child_sa_create(host_t *me, host_t* other,
|
2007-06-27 13:10:55 +00:00
|
|
|
child_cfg_t *config, u_int32_t rekey, bool encap)
|
2006-02-16 09:55:07 +00:00
|
|
|
{
|
2007-02-28 14:04:36 +00:00
|
|
|
static u_int32_t reqid = 0;
|
2010-07-12 07:38:39 +00:00
|
|
|
private_child_sa_t *this;
|
|
|
|
|
|
|
|
INIT(this,
|
|
|
|
.public = {
|
|
|
|
.get_name = _get_name,
|
|
|
|
.get_reqid = _get_reqid,
|
|
|
|
.get_config = _get_config,
|
|
|
|
.get_state = _get_state,
|
|
|
|
.set_state = _set_state,
|
|
|
|
.get_spi = _get_spi,
|
|
|
|
.get_cpi = _get_cpi,
|
|
|
|
.get_protocol = _get_protocol,
|
|
|
|
.set_protocol = _set_protocol,
|
|
|
|
.get_mode = _get_mode,
|
|
|
|
.set_mode = _set_mode,
|
|
|
|
.get_proposal = _get_proposal,
|
|
|
|
.set_proposal = _set_proposal,
|
|
|
|
.get_lifetime = _get_lifetime,
|
|
|
|
.get_usestats = _get_usestats,
|
|
|
|
.has_encap = _has_encap,
|
|
|
|
.get_ipcomp = _get_ipcomp,
|
|
|
|
.set_ipcomp = _set_ipcomp,
|
|
|
|
.get_close_action = _get_close_action,
|
|
|
|
.set_close_action = _set_close_action,
|
|
|
|
.get_dpd_action = _get_dpd_action,
|
|
|
|
.set_dpd_action = _set_dpd_action,
|
|
|
|
.alloc_spi = _alloc_spi,
|
|
|
|
.alloc_cpi = _alloc_cpi,
|
|
|
|
.install = _install,
|
|
|
|
.update = _update,
|
|
|
|
.add_policies = _add_policies,
|
|
|
|
.get_traffic_selectors = _get_traffic_selectors,
|
|
|
|
.create_policy_enumerator = _create_policy_enumerator,
|
|
|
|
.destroy = _destroy,
|
|
|
|
},
|
|
|
|
.my_addr = me->clone(me),
|
|
|
|
.other_addr = other->clone(other),
|
|
|
|
.encap = encap,
|
|
|
|
.ipcomp = IPCOMP_NONE,
|
|
|
|
.state = CHILD_CREATED,
|
|
|
|
.my_ts = linked_list_create(),
|
|
|
|
.other_ts = linked_list_create(),
|
|
|
|
.protocol = PROTO_NONE,
|
|
|
|
.mode = MODE_TUNNEL,
|
|
|
|
.close_action = config->get_close_action(config),
|
|
|
|
.dpd_action = config->get_dpd_action(config),
|
|
|
|
.reqid = config->get_reqid(config),
|
|
|
|
.mark_in = config->get_mark(config, TRUE),
|
|
|
|
.mark_out = config->get_mark(config, FALSE),
|
|
|
|
);
|
|
|
|
|
2007-04-10 06:01:03 +00:00
|
|
|
this->config = config;
|
|
|
|
config->get_ref(config);
|
2010-07-02 21:45:57 +00:00
|
|
|
|
2010-04-22 15:03:30 +00:00
|
|
|
if (!this->reqid)
|
|
|
|
{
|
|
|
|
/* reuse old reqid if we are rekeying an existing CHILD_SA */
|
|
|
|
this->reqid = rekey ? rekey : ++reqid;
|
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-06 13:14:54 +00:00
|
|
|
/* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
|
2008-11-11 06:37:37 +00:00
|
|
|
if (config->get_mode(config) == MODE_TRANSPORT &&
|
2009-09-04 12:50:23 +00:00
|
|
|
config->use_proxy_mode(config))
|
2008-11-11 06:37:37 +00:00
|
|
|
{
|
|
|
|
ts_type_t type;
|
|
|
|
int family;
|
|
|
|
chunk_t addr;
|
|
|
|
host_t *host;
|
|
|
|
enumerator_t *enumerator;
|
|
|
|
linked_list_t *my_ts_list, *other_ts_list;
|
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
this->mode = MODE_TRANSPORT;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me);
|
|
|
|
enumerator = my_ts_list->create_enumerator(my_ts_list);
|
|
|
|
if (enumerator->enumerate(enumerator, &my_ts))
|
|
|
|
{
|
|
|
|
if (my_ts->is_host(my_ts, NULL) &&
|
|
|
|
!my_ts->is_host(my_ts, this->my_addr))
|
|
|
|
{
|
|
|
|
type = my_ts->get_type(my_ts);
|
|
|
|
family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
|
|
|
|
addr = my_ts->get_from_address(my_ts);
|
|
|
|
host = host_create_from_chunk(family, addr, 0);
|
|
|
|
free(addr.ptr);
|
|
|
|
DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H",
|
2009-08-06 13:14:54 +00:00
|
|
|
this->my_addr, host);
|
2008-11-11 06:37:37 +00:00
|
|
|
this->my_addr->destroy(this->my_addr);
|
|
|
|
this->my_addr = host;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
|
|
|
my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy));
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other);
|
|
|
|
enumerator = other_ts_list->create_enumerator(other_ts_list);
|
|
|
|
if (enumerator->enumerate(enumerator, &other_ts))
|
|
|
|
{
|
|
|
|
if (other_ts->is_host(other_ts, NULL) &&
|
|
|
|
!other_ts->is_host(other_ts, this->other_addr))
|
|
|
|
{
|
|
|
|
type = other_ts->get_type(other_ts);
|
|
|
|
family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
|
|
|
|
addr = other_ts->get_from_address(other_ts);
|
|
|
|
host = host_create_from_chunk(family, addr, 0);
|
|
|
|
free(addr.ptr);
|
|
|
|
DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H",
|
2009-08-06 13:14:54 +00:00
|
|
|
this->other_addr, host);
|
2008-11-11 06:37:37 +00:00
|
|
|
this->other_addr->destroy(this->other_addr);
|
|
|
|
this->other_addr = host;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
|
|
|
other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy));
|
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-06-22 06:36:28 +00:00
|
|
|
return &this->public;
|
2005-12-04 19:05:52 +00:00
|
|
|
}
|