2005-12-04 19:05:52 +00:00
|
|
|
/*
|
2017-02-28 13:44:38 +00:00
|
|
|
* Copyright (C) 2006-2017 Tobias Brunner
|
2017-03-22 12:13:56 +00:00
|
|
|
* Copyright (C) 2016 Andreas Steffen
|
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
|
2016-03-31 14:01:40 +00:00
|
|
|
* HSR Hochschule fuer Technik Rapperswil
|
2005-12-04 19:05:52 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
2006-02-10 08:20:06 +00:00
|
|
|
#include <daemon.h>
|
2013-07-17 08:08:19 +00:00
|
|
|
#include <collections/array.h>
|
2006-02-10 08:20:06 +00:00
|
|
|
|
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",
|
2015-03-24 17:36:49 +00:00
|
|
|
"REKEYED",
|
2014-11-03 08:38:27 +00:00
|
|
|
"RETRYING",
|
2006-10-18 11:46:13 +00:00
|
|
|
"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
|
|
|
|
2017-03-21 14:08:14 +00:00
|
|
|
ENUM(child_sa_outbound_state_names, CHILD_OUTBOUND_NONE, CHILD_OUTBOUND_INSTALLED,
|
|
|
|
"NONE",
|
|
|
|
"REGISTERED",
|
|
|
|
"INSTALLED",
|
|
|
|
);
|
|
|
|
|
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
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_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
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_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
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint16_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
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint16_t other_cpi;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-03-01 15:56:51 +00:00
|
|
|
/**
|
2013-07-17 08:08:19 +00:00
|
|
|
* Array for local traffic selectors
|
2006-03-01 15:56:51 +00:00
|
|
|
*/
|
2013-07-17 08:08:19 +00:00
|
|
|
array_t *my_ts;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-10-29 16:06:16 +00:00
|
|
|
/**
|
2013-07-17 08:08:19 +00:00
|
|
|
* Array for remote traffic selectors
|
2008-10-29 16:06:16 +00:00
|
|
|
*/
|
2013-07-17 08:08:19 +00:00
|
|
|
array_t *other_ts;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-02-28 14:03:12 +00:00
|
|
|
/**
|
|
|
|
* Outbound encryption key cached during a rekeying
|
|
|
|
*/
|
|
|
|
chunk_t encr_r;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Outbound integrity key cached during a rekeying
|
|
|
|
*/
|
|
|
|
chunk_t integ_r;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether the outbound SA has only been registered yet during a rekeying
|
|
|
|
*/
|
2017-03-21 14:08:14 +00:00
|
|
|
child_sa_outbound_state_t outbound_state;
|
2017-02-28 14:03:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether the peer supports TFCv3
|
|
|
|
*/
|
|
|
|
bool tfcv3;
|
|
|
|
|
2017-02-28 14:03:45 +00:00
|
|
|
/**
|
|
|
|
* The outbound SPI of the CHILD_SA that replaced this one during a rekeying
|
|
|
|
*/
|
|
|
|
uint32_t rekey_spi;
|
|
|
|
|
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
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_t reqid;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2014-10-21 09:36:18 +00:00
|
|
|
/**
|
|
|
|
* Did we allocate/confirm and must release the reqid?
|
|
|
|
*/
|
|
|
|
bool reqid_allocated;
|
|
|
|
|
2015-07-31 14:51:35 +00:00
|
|
|
/**
|
|
|
|
* Is the reqid statically configured
|
|
|
|
*/
|
|
|
|
bool static_reqid;
|
|
|
|
|
2016-08-18 13:09:08 +00:00
|
|
|
/**
|
2014-10-23 09:27:25 +00:00
|
|
|
* Unique CHILD_SA identifier
|
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_t unique_id;
|
2014-10-23 09:27:25 +00:00
|
|
|
|
2016-08-18 13:09:08 +00:00
|
|
|
/**
|
|
|
|
* Whether FWD policieis in the outbound direction should be installed
|
|
|
|
*/
|
|
|
|
bool policies_fwd_out;
|
|
|
|
|
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
|
|
|
|
2013-11-07 08:20:40 +00:00
|
|
|
/**
|
|
|
|
* absolute time when SA has been installed
|
|
|
|
*/
|
|
|
|
time_t install_time;
|
|
|
|
|
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
|
|
|
|
2012-06-04 15:43:38 +00:00
|
|
|
/**
|
|
|
|
* TRUE if this CHILD_SA is used to install trap policies
|
|
|
|
*/
|
|
|
|
bool trap;
|
|
|
|
|
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)
|
|
|
|
*/
|
2013-09-23 10:28:13 +00:00
|
|
|
time_t my_usetime;
|
2009-07-30 21:19:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* time of last use in seconds (outbound)
|
|
|
|
*/
|
2013-09-23 10:28:13 +00:00
|
|
|
time_t other_usetime;
|
2009-07-30 21:19:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* last number of inbound bytes
|
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint64_t my_usebytes;
|
2009-07-30 21:19:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* last number of outbound bytes
|
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint64_t other_usebytes;
|
2013-03-13 10:31:36 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* last number of inbound packets
|
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint64_t my_usepackets;
|
2013-03-13 10:31:36 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* last number of outbound bytes
|
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint64_t other_usepackets;
|
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.
|
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
static inline uint8_t proto_ike2ip(protocol_id_t protocol)
|
2010-07-12 08:35:19 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-03-22 12:22:01 +00:00
|
|
|
METHOD(child_sa_t, get_reqid, uint32_t,
|
2010-07-12 07:38:39 +00:00
|
|
|
private_child_sa_t *this)
|
2006-05-31 14:23:15 +00:00
|
|
|
{
|
|
|
|
return this->reqid;
|
|
|
|
}
|
2008-11-19 15:31:27 +00:00
|
|
|
|
2016-03-22 12:22:01 +00:00
|
|
|
METHOD(child_sa_t, get_unique_id, uint32_t,
|
2014-10-23 09:27:25 +00:00
|
|
|
private_child_sa_t *this)
|
|
|
|
{
|
|
|
|
return this->unique_id;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2017-03-01 15:07:57 +00:00
|
|
|
DBG2(DBG_CHD, "CHILD_SA %s{%d} state change: %N => %N",
|
|
|
|
get_name(this), this->unique_id,
|
|
|
|
child_sa_state_names, this->state,
|
|
|
|
child_sa_state_names, 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;
|
|
|
|
}
|
|
|
|
|
2017-03-21 14:08:14 +00:00
|
|
|
METHOD(child_sa_t, get_outbound_state, child_sa_outbound_state_t,
|
|
|
|
private_child_sa_t *this)
|
|
|
|
{
|
|
|
|
return this->outbound_state;
|
|
|
|
}
|
|
|
|
|
2016-03-22 12:22:01 +00:00
|
|
|
METHOD(child_sa_t, get_spi, uint32_t,
|
2010-07-12 07:38:39 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-03-22 12:22:01 +00:00
|
|
|
METHOD(child_sa_t, get_cpi, uint16_t,
|
2010-07-12 07:38:39 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-07-17 08:01:22 +00:00
|
|
|
METHOD(child_sa_t, create_ts_enumerator, enumerator_t*,
|
|
|
|
private_child_sa_t *this, bool local)
|
2008-11-19 15:31:27 +00:00
|
|
|
{
|
2013-07-17 08:01:22 +00:00
|
|
|
if (local)
|
|
|
|
{
|
2013-07-17 08:08:19 +00:00
|
|
|
return array_create_enumerator(this->my_ts);
|
2013-07-17 08:01:22 +00:00
|
|
|
}
|
2013-07-17 08:08:19 +00:00
|
|
|
return array_create_enumerator(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;
|
2013-07-17 08:08:19 +00:00
|
|
|
/** array of others TS, to recreate enumerator */
|
|
|
|
array_t *array;
|
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,
|
2017-05-11 07:17:02 +00:00
|
|
|
policy_enumerator_t *this, va_list args)
|
2008-10-15 12:24:44 +00:00
|
|
|
{
|
2017-05-11 07:17:02 +00:00
|
|
|
traffic_selector_t *other_ts, **my_out, **other_out;
|
|
|
|
|
|
|
|
VA_ARGS_VGET(args, my_out, other_out);
|
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);
|
2013-07-17 08:08:19 +00:00
|
|
|
this->other = array_create_enumerator(this->array);
|
2008-10-21 10:57:40 +00:00
|
|
|
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
|
|
|
}
|
2015-09-16 14:44:09 +00:00
|
|
|
if (my_out)
|
|
|
|
{
|
|
|
|
*my_out = this->ts;
|
|
|
|
}
|
|
|
|
if (other_out)
|
|
|
|
{
|
|
|
|
*other_out = other_ts;
|
|
|
|
}
|
2008-10-21 10:57:40 +00:00
|
|
|
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 = {
|
2017-05-11 07:17:02 +00:00
|
|
|
.enumerate = enumerator_enumerate_default,
|
|
|
|
.venumerate = _policy_enumerate,
|
2010-07-12 07:38:39 +00:00
|
|
|
.destroy = _policy_destroy,
|
|
|
|
},
|
2013-07-17 08:08:19 +00:00
|
|
|
.mine = array_create_enumerator(this->my_ts),
|
|
|
|
.other = array_create_enumerator(this->other_ts),
|
|
|
|
.array = this->other_ts,
|
2010-07-12 07:38:39 +00:00
|
|
|
.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;
|
2016-03-22 12:22:01 +00:00
|
|
|
uint64_t bytes, packets;
|
2013-09-23 10:28:13 +00:00
|
|
|
time_t time;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-06 13:14:54 +00:00
|
|
|
if (inbound)
|
|
|
|
{
|
|
|
|
if (this->my_spi)
|
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_sa_id_t id = {
|
|
|
|
.src = this->other_addr,
|
|
|
|
.dst = this->my_addr,
|
|
|
|
.spi = this->my_spi,
|
|
|
|
.proto = proto_ike2ip(this->protocol),
|
|
|
|
};
|
|
|
|
kernel_ipsec_query_sa_t query = {};
|
|
|
|
|
|
|
|
status = charon->kernel->query_sa(charon->kernel, &id, &query,
|
|
|
|
&bytes, &packets, &time);
|
2009-08-06 13:14:54 +00:00
|
|
|
if (status == SUCCESS)
|
|
|
|
{
|
|
|
|
if (bytes > this->my_usebytes)
|
|
|
|
{
|
|
|
|
this->my_usebytes = bytes;
|
2013-03-13 10:31:36 +00:00
|
|
|
this->my_usepackets = packets;
|
2013-04-21 15:05:08 +00:00
|
|
|
if (time)
|
|
|
|
{
|
|
|
|
this->my_usetime = time;
|
|
|
|
}
|
2009-08-06 13:14:54 +00:00
|
|
|
}
|
2016-11-15 17:27:55 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
status = FAILED;
|
|
|
|
}
|
2009-08-06 13:14:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-21 14:08:14 +00:00
|
|
|
if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED)
|
2009-08-06 13:14:54 +00:00
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_sa_id_t id = {
|
|
|
|
.src = this->my_addr,
|
|
|
|
.dst = this->other_addr,
|
|
|
|
.spi = this->other_spi,
|
|
|
|
.proto = proto_ike2ip(this->protocol),
|
|
|
|
.mark = this->mark_out,
|
|
|
|
};
|
|
|
|
kernel_ipsec_query_sa_t query = {};
|
|
|
|
|
|
|
|
status = charon->kernel->query_sa(charon->kernel, &id, &query,
|
|
|
|
&bytes, &packets, &time);
|
2009-08-06 13:14:54 +00:00
|
|
|
if (status == SUCCESS)
|
|
|
|
{
|
|
|
|
if (bytes > this->other_usebytes)
|
|
|
|
{
|
|
|
|
this->other_usebytes = bytes;
|
2013-03-13 10:31:36 +00:00
|
|
|
this->other_usepackets = packets;
|
2013-04-21 15:05:08 +00:00
|
|
|
if (time)
|
|
|
|
{
|
|
|
|
this->other_usetime = time;
|
|
|
|
}
|
2009-08-06 13:14:54 +00:00
|
|
|
}
|
2016-11-15 17:27:55 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
status = FAILED;
|
|
|
|
}
|
2009-08-06 13:14:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
*/
|
2013-04-21 15:05:08 +00:00
|
|
|
static bool 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;
|
2013-09-23 10:35:33 +00:00
|
|
|
time_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
|
|
|
{
|
2013-09-23 10:35:33 +00:00
|
|
|
time_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
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_policy_id_t id = {
|
|
|
|
.dir = POLICY_IN,
|
|
|
|
.src_ts = other_ts,
|
|
|
|
.dst_ts = my_ts,
|
|
|
|
.mark = this->mark_in,
|
|
|
|
};
|
|
|
|
kernel_ipsec_query_policy_t query = {};
|
|
|
|
|
|
|
|
if (charon->kernel->query_policy(charon->kernel, &id, &query,
|
|
|
|
&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
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
id.dir = POLICY_FWD;
|
|
|
|
if (charon->kernel->query_policy(charon->kernel, &id, &query,
|
|
|
|
&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
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_policy_id_t id = {
|
|
|
|
.dir = POLICY_OUT,
|
|
|
|
.src_ts = my_ts,
|
|
|
|
.dst_ts = other_ts,
|
|
|
|
.mark = this->mark_out,
|
2016-03-27 08:18:19 +00:00
|
|
|
.interface = this->config->get_interface(this->config),
|
2016-03-31 14:01:40 +00:00
|
|
|
};
|
|
|
|
kernel_ipsec_query_policy_t query = {};
|
|
|
|
|
|
|
|
if (charon->kernel->query_policy(charon->kernel, &id, &query,
|
|
|
|
&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)
|
|
|
|
{
|
2013-04-21 15:05:08 +00:00
|
|
|
return FALSE;
|
2009-08-07 03:59:09 +00:00
|
|
|
}
|
2009-07-30 21:19:42 +00:00
|
|
|
if (inbound)
|
|
|
|
{
|
|
|
|
this->my_usetime = last_use;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->other_usetime = last_use;
|
|
|
|
}
|
2013-04-21 15:05:08 +00:00
|
|
|
return TRUE;
|
2008-10-24 08:02:35 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, get_usestats, void,
|
2013-03-13 10:38:02 +00:00
|
|
|
private_child_sa_t *this, bool inbound,
|
2016-03-22 12:22:01 +00:00
|
|
|
time_t *time, uint64_t *bytes, uint64_t *packets)
|
2009-07-30 19:33:19 +00:00
|
|
|
{
|
2013-04-21 14:50:17 +00:00
|
|
|
if ((!bytes && !packets) || 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.
|
|
|
|
*/
|
2013-04-21 14:50:17 +00:00
|
|
|
if (time)
|
|
|
|
{
|
2013-04-21 15:05:08 +00:00
|
|
|
if (!update_usetime(this, inbound) && !bytes && !packets)
|
|
|
|
{
|
|
|
|
/* if policy query did not yield a usetime, query SAs instead */
|
|
|
|
update_usebytes(this, inbound);
|
|
|
|
}
|
2013-04-21 14:50:17 +00:00
|
|
|
}
|
2009-08-06 14:46:02 +00:00
|
|
|
}
|
|
|
|
if (time)
|
|
|
|
{
|
|
|
|
*time = inbound ? this->my_usetime : this->other_usetime;
|
|
|
|
}
|
|
|
|
if (bytes)
|
|
|
|
{
|
|
|
|
*bytes = inbound ? this->my_usebytes : this->other_usebytes;
|
|
|
|
}
|
2013-03-13 10:38:02 +00:00
|
|
|
if (packets)
|
|
|
|
{
|
|
|
|
*packets = inbound ? this->my_usepackets : this->other_usepackets;
|
|
|
|
}
|
2009-07-30 19:33:19 +00:00
|
|
|
}
|
|
|
|
|
2012-03-21 15:54:24 +00:00
|
|
|
METHOD(child_sa_t, get_mark, mark_t,
|
|
|
|
private_child_sa_t *this, bool inbound)
|
|
|
|
{
|
|
|
|
if (inbound)
|
|
|
|
{
|
|
|
|
return this->mark_in;
|
|
|
|
}
|
|
|
|
return this->mark_out;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-11-07 08:20:40 +00:00
|
|
|
METHOD(child_sa_t, get_installtime, time_t,
|
|
|
|
private_child_sa_t *this)
|
|
|
|
{
|
|
|
|
return this->install_time;
|
|
|
|
}
|
|
|
|
|
2016-03-22 12:22:01 +00:00
|
|
|
METHOD(child_sa_t, alloc_spi, uint32_t,
|
2010-07-12 07:38:39 +00:00
|
|
|
private_child_sa_t *this, protocol_id_t protocol)
|
2006-06-22 06:36:28 +00:00
|
|
|
{
|
2016-02-12 14:30:18 +00:00
|
|
|
if (charon->kernel->get_spi(charon->kernel, this->other_addr, this->my_addr,
|
|
|
|
proto_ike2ip(protocol), &this->my_spi) == SUCCESS)
|
2009-05-14 08:28:18 +00:00
|
|
|
{
|
2013-06-20 14:13:35 +00:00
|
|
|
/* if we allocate a SPI, but then are unable to establish the SA, we
|
|
|
|
* need to know the protocol family to delete the partial SA */
|
|
|
|
this->protocol = protocol;
|
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
|
|
|
}
|
|
|
|
|
2016-03-22 12:22:01 +00:00
|
|
|
METHOD(child_sa_t, alloc_cpi, uint16_t,
|
2010-07-12 07:38:39 +00:00
|
|
|
private_child_sa_t *this)
|
2005-12-04 19:05:52 +00:00
|
|
|
{
|
2016-02-12 14:30:18 +00:00
|
|
|
if (charon->kernel->get_cpi(charon->kernel, this->other_addr, this->my_addr,
|
|
|
|
&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
|
|
|
}
|
|
|
|
|
2017-02-28 14:03:12 +00:00
|
|
|
/**
|
|
|
|
* Install the given SA in the kernel
|
|
|
|
*/
|
|
|
|
static status_t install_internal(private_child_sa_t *this, chunk_t encr,
|
|
|
|
chunk_t integ, uint32_t spi, uint16_t cpi, bool initiator, bool inbound,
|
|
|
|
bool tfcv3)
|
2005-12-04 19:05:52 +00:00
|
|
|
{
|
2016-03-22 12:22:01 +00:00
|
|
|
uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
|
|
|
|
uint16_t esn = NO_EXT_SEQ_NUMBERS;
|
2017-03-01 13:40:15 +00:00
|
|
|
linked_list_t *my_ts, *other_ts, *src_ts, *dst_ts;
|
2009-08-27 09:45:36 +00:00
|
|
|
time_t now;
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_sa_id_t id;
|
|
|
|
kernel_ipsec_add_sa_t sa;
|
2009-08-27 09:45:36 +00:00
|
|
|
lifetime_cfg_t *lifetime;
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_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;
|
2015-03-09 16:52:33 +00:00
|
|
|
bool update = FALSE;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-03-01 13:40:15 +00:00
|
|
|
/* BEET requires the bound address from the traffic selectors */
|
|
|
|
my_ts = linked_list_create_from_enumerator(
|
|
|
|
array_create_enumerator(this->my_ts));
|
|
|
|
other_ts = linked_list_create_from_enumerator(
|
|
|
|
array_create_enumerator(this->other_ts));
|
|
|
|
|
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;
|
2015-03-09 16:52:33 +00:00
|
|
|
if (this->my_spi == spi)
|
|
|
|
{ /* alloc_spi has been called, do an SA update */
|
|
|
|
update = TRUE;
|
|
|
|
}
|
2008-11-19 15:31:27 +00:00
|
|
|
this->my_spi = spi;
|
|
|
|
this->my_cpi = cpi;
|
2017-03-01 13:40:15 +00:00
|
|
|
dst_ts = my_ts;
|
|
|
|
src_ts = other_ts;
|
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;
|
2017-03-01 13:40:15 +00:00
|
|
|
src_ts = my_ts;
|
|
|
|
dst_ts = other_ts;
|
2010-12-08 12:41:04 +00:00
|
|
|
|
2010-12-08 12:41:51 +00:00
|
|
|
if (tfcv3)
|
|
|
|
{
|
|
|
|
tfc = this->config->get_tfc(this->config);
|
|
|
|
}
|
2017-03-21 14:08:14 +00:00
|
|
|
this->outbound_state = CHILD_OUTBOUND_INSTALLED;
|
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);
|
2011-04-18 13:41:23 +00:00
|
|
|
this->proposal->get_algorithm(this->proposal, EXTENDED_SEQUENCE_NUMBERS,
|
|
|
|
&esn, NULL);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-05-10 17:15:53 +00:00
|
|
|
if (int_alg == AUTH_HMAC_SHA2_256_128 &&
|
|
|
|
this->config->has_option(this->config, OPT_SHA256_96))
|
|
|
|
{
|
|
|
|
DBG2(DBG_CHD, " using %N with 96-bit truncation",
|
|
|
|
integrity_algorithm_names, int_alg);
|
|
|
|
int_alg = AUTH_HMAC_SHA2_256_96;
|
|
|
|
}
|
|
|
|
|
2015-07-31 14:51:35 +00:00
|
|
|
if (!this->reqid_allocated && !this->static_reqid)
|
2014-10-21 09:36:18 +00:00
|
|
|
{
|
2016-02-12 14:30:18 +00:00
|
|
|
status = charon->kernel->alloc_reqid(charon->kernel, my_ts, other_ts,
|
|
|
|
this->mark_in, this->mark_out, &this->reqid);
|
2014-10-21 09:36:18 +00:00
|
|
|
if (status != SUCCESS)
|
|
|
|
{
|
2017-03-01 13:40:15 +00:00
|
|
|
my_ts->destroy(my_ts);
|
|
|
|
other_ts->destroy(other_ts);
|
2014-10-21 09:36:18 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
this->reqid_allocated = TRUE;
|
|
|
|
}
|
|
|
|
|
2016-05-03 15:33:43 +00:00
|
|
|
lifetime = this->config->get_lifetime(this->config, TRUE);
|
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
|
|
|
{
|
2012-06-05 14:16:07 +00:00
|
|
|
if (this->rekey_time)
|
|
|
|
{
|
|
|
|
this->rekey_time = min(this->rekey_time, now + lifetime->time.rekey);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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
|
|
|
|
2016-03-31 14:01:40 +00:00
|
|
|
id = (kernel_ipsec_sa_id_t){
|
|
|
|
.src = src,
|
|
|
|
.dst = dst,
|
|
|
|
.spi = spi,
|
|
|
|
.proto = proto_ike2ip(this->protocol),
|
child-sa: Do not install mark on inbound kernel SA
The SA ID (src, dst, proto, spi) is unique on ingress.
As such, explicit inbound marking is not needed to match an SA.
On the other hand, requiring inbound SAs to use marks forces the
installation of a mechanism for marking traffic (e.g. iptables) based
on some criteria.
Defining the criteria becomes complicated, for example when required to
support multiple SAs from the same src, especially when traffic is UDP
encapsulated.
This commit removes the assignment of the child_sa mark_in to the inbound SA.
Policies can be arbitrated by existing means - e.g, via netfilter policy
matching or using VTI interfaces - without the need to classify the flows prior
to state matching.
Since the reqid allocator regards the mark value, there is no risk of matching
the wrong policy.
And as explicit marking was required for route-based VPN to work before this
change, it should not cause regressions in existing setups.
Closes strongswan/strongswan#59.
2017-01-25 10:26:42 +00:00
|
|
|
.mark = inbound ? (mark_t){} : this->mark_out,
|
2016-03-31 14:01:40 +00:00
|
|
|
};
|
|
|
|
sa = (kernel_ipsec_add_sa_t){
|
|
|
|
.reqid = this->reqid,
|
|
|
|
.mode = this->mode,
|
|
|
|
.src_ts = src_ts,
|
|
|
|
.dst_ts = dst_ts,
|
2016-03-27 08:18:19 +00:00
|
|
|
.interface = inbound ? NULL : this->config->get_interface(this->config),
|
2016-03-31 14:01:40 +00:00
|
|
|
.lifetime = lifetime,
|
|
|
|
.enc_alg = enc_alg,
|
|
|
|
.enc_key = encr,
|
|
|
|
.int_alg = int_alg,
|
|
|
|
.int_key = integ,
|
|
|
|
.replay_window = this->config->get_replay_window(this->config),
|
|
|
|
.tfc = tfc,
|
|
|
|
.ipcomp = this->ipcomp,
|
|
|
|
.cpi = cpi,
|
|
|
|
.encap = this->encap,
|
2016-06-20 13:27:22 +00:00
|
|
|
.hw_offload = this->config->has_option(this->config, OPT_HW_OFFLOAD),
|
2016-03-31 14:01:40 +00:00
|
|
|
.esn = esn,
|
|
|
|
.initiator = initiator,
|
|
|
|
.inbound = inbound,
|
|
|
|
.update = update,
|
|
|
|
};
|
|
|
|
|
|
|
|
status = charon->kernel->add_sa(charon->kernel, &id, &sa);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-03-01 13:40:15 +00:00
|
|
|
my_ts->destroy(my_ts);
|
|
|
|
other_ts->destroy(other_ts);
|
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
|
|
|
}
|
|
|
|
|
2017-02-28 14:03:12 +00:00
|
|
|
METHOD(child_sa_t, install, status_t,
|
|
|
|
private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
|
|
|
|
uint16_t cpi, bool initiator, bool inbound, bool tfcv3)
|
|
|
|
{
|
|
|
|
return install_internal(this, encr, integ, spi, cpi, initiator, inbound,
|
|
|
|
tfcv3);
|
|
|
|
}
|
|
|
|
|
2013-12-11 14:57:46 +00:00
|
|
|
/**
|
|
|
|
* Check kernel interface if policy updates are required
|
|
|
|
*/
|
|
|
|
static bool require_policy_update()
|
|
|
|
{
|
|
|
|
kernel_feature_t f;
|
|
|
|
|
2016-02-12 14:30:18 +00:00
|
|
|
f = charon->kernel->get_features(charon->kernel);
|
2013-12-11 14:57:46 +00:00
|
|
|
return !(f & KERNEL_NO_POLICY_UPDATES);
|
|
|
|
}
|
|
|
|
|
2015-09-16 14:44:09 +00:00
|
|
|
/**
|
|
|
|
* Prepare SA config to install/delete policies
|
|
|
|
*/
|
|
|
|
static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa,
|
|
|
|
ipsec_sa_cfg_t *other_sa)
|
|
|
|
{
|
|
|
|
enumerator_t *enumerator;
|
|
|
|
|
|
|
|
*my_sa = (ipsec_sa_cfg_t){
|
|
|
|
.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;
|
|
|
|
|
|
|
|
if (this->protocol == PROTO_ESP)
|
|
|
|
{
|
|
|
|
my_sa->esp.use = TRUE;
|
|
|
|
my_sa->esp.spi = this->my_spi;
|
|
|
|
other_sa->esp.use = TRUE;
|
|
|
|
other_sa->esp.spi = this->other_spi;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
my_sa->ah.use = TRUE;
|
|
|
|
my_sa->ah.spi = this->my_spi;
|
|
|
|
other_sa->ah.use = TRUE;
|
|
|
|
other_sa->ah.spi = this->other_spi;
|
|
|
|
}
|
|
|
|
|
|
|
|
enumerator = create_policy_enumerator(this);
|
|
|
|
while (enumerator->enumerate(enumerator, NULL, NULL))
|
|
|
|
{
|
|
|
|
my_sa->policy_count++;
|
|
|
|
other_sa->policy_count++;
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
|
|
|
}
|
|
|
|
|
2011-07-28 12:24:42 +00:00
|
|
|
/**
|
2017-02-28 13:44:38 +00:00
|
|
|
* Install inbound policie(s): in, fwd
|
2011-07-28 12:24:42 +00:00
|
|
|
*/
|
2017-02-28 13:44:38 +00:00
|
|
|
static status_t install_policies_inbound(private_child_sa_t *this,
|
2011-07-28 12:24:42 +00:00
|
|
|
host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
|
|
|
|
traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
|
2016-03-24 17:35:27 +00:00
|
|
|
ipsec_sa_cfg_t *other_sa, policy_type_t type,
|
|
|
|
policy_priority_t priority, uint32_t manual_prio)
|
2011-07-28 12:24:42 +00:00
|
|
|
{
|
2017-02-28 13:44:38 +00:00
|
|
|
kernel_ipsec_policy_id_t in_id = {
|
2016-03-31 14:01:40 +00:00
|
|
|
.dir = POLICY_IN,
|
|
|
|
.src_ts = other_ts,
|
|
|
|
.dst_ts = my_ts,
|
|
|
|
.mark = this->mark_in,
|
|
|
|
};
|
2017-02-28 13:44:38 +00:00
|
|
|
kernel_ipsec_manage_policy_t in_policy = {
|
2016-03-31 14:01:40 +00:00
|
|
|
.type = type,
|
|
|
|
.prio = priority,
|
2016-03-24 17:35:27 +00:00
|
|
|
.manual_prio = manual_prio,
|
2016-03-31 14:01:40 +00:00
|
|
|
.src = other_addr,
|
|
|
|
.dst = my_addr,
|
|
|
|
.sa = my_sa,
|
|
|
|
};
|
2011-07-28 12:24:42 +00:00
|
|
|
status_t status = SUCCESS;
|
2016-03-31 14:01:40 +00:00
|
|
|
|
|
|
|
status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
|
2011-07-28 12:24:42 +00:00
|
|
|
if (this->mode != MODE_TRANSPORT)
|
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
in_id.dir = POLICY_FWD;
|
|
|
|
status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
|
2017-02-28 13:44:38 +00:00
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
2016-04-01 14:41:05 +00:00
|
|
|
|
2017-02-28 13:44:38 +00:00
|
|
|
/**
|
|
|
|
* Install outbound policie(s): out, [fwd]
|
|
|
|
*/
|
|
|
|
static status_t install_policies_outbound(private_child_sa_t *this,
|
|
|
|
host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
|
|
|
|
traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
|
|
|
|
ipsec_sa_cfg_t *other_sa, policy_type_t type,
|
|
|
|
policy_priority_t priority, uint32_t manual_prio)
|
|
|
|
{
|
|
|
|
kernel_ipsec_policy_id_t out_id = {
|
|
|
|
.dir = POLICY_OUT,
|
|
|
|
.src_ts = my_ts,
|
|
|
|
.dst_ts = other_ts,
|
|
|
|
.mark = this->mark_out,
|
|
|
|
.interface = this->config->get_interface(this->config),
|
|
|
|
};
|
|
|
|
kernel_ipsec_manage_policy_t out_policy = {
|
|
|
|
.type = type,
|
|
|
|
.prio = priority,
|
|
|
|
.manual_prio = manual_prio,
|
|
|
|
.src = my_addr,
|
|
|
|
.dst = other_addr,
|
|
|
|
.sa = other_sa,
|
|
|
|
};
|
|
|
|
status_t status = SUCCESS;
|
|
|
|
|
|
|
|
status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy);
|
|
|
|
|
|
|
|
if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
|
|
|
|
{
|
2016-04-01 14:41:05 +00:00
|
|
|
/* install an "outbound" FWD policy in case there is a drop policy
|
|
|
|
* matching outbound forwarded traffic, to allow another tunnel to use
|
|
|
|
* the reversed subnets and do the same we don't set a reqid (this also
|
|
|
|
* allows the kernel backend to distinguish between the two types of
|
2016-05-02 12:21:30 +00:00
|
|
|
* FWD policies). To avoid problems with symmetrically overlapping
|
|
|
|
* policies of two SAs we install them with reduced priority. As they
|
|
|
|
* basically act as bypass policies for drop policies we use a higher
|
|
|
|
* priority than is used for them. */
|
2017-02-28 13:44:38 +00:00
|
|
|
out_id.dir = POLICY_FWD;
|
|
|
|
other_sa->reqid = 0;
|
|
|
|
if (priority == POLICY_PRIORITY_DEFAULT)
|
2016-05-02 12:21:30 +00:00
|
|
|
{
|
2017-02-28 13:44:38 +00:00
|
|
|
out_policy.prio = POLICY_PRIORITY_ROUTED;
|
2016-05-02 12:21:30 +00:00
|
|
|
}
|
2017-02-28 13:44:38 +00:00
|
|
|
status |= charon->kernel->add_policy(charon->kernel, &out_id,
|
|
|
|
&out_policy);
|
|
|
|
/* reset the reqid for any other further policies */
|
|
|
|
other_sa->reqid = this->reqid;
|
2011-07-28 12:24:42 +00:00
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-02-28 13:44:38 +00:00
|
|
|
* Install all policies
|
2011-07-28 12:24:42 +00:00
|
|
|
*/
|
2017-02-28 13:44:38 +00:00
|
|
|
static status_t install_policies_internal(private_child_sa_t *this,
|
|
|
|
host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
|
|
|
|
traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
|
|
|
|
ipsec_sa_cfg_t *other_sa, policy_type_t type,
|
|
|
|
policy_priority_t priority, uint32_t manual_prio)
|
|
|
|
{
|
|
|
|
status_t status = SUCCESS;
|
|
|
|
|
|
|
|
status |= install_policies_inbound(this, my_addr, other_addr, my_ts,
|
|
|
|
other_ts, my_sa, other_sa, type,
|
|
|
|
priority, manual_prio);
|
|
|
|
status |= install_policies_outbound(this, my_addr, other_addr, my_ts,
|
|
|
|
other_ts, my_sa, other_sa, type,
|
|
|
|
priority, manual_prio);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete inbound policies: in, fwd
|
|
|
|
*/
|
|
|
|
static void del_policies_inbound(private_child_sa_t *this,
|
2015-09-16 14:44:09 +00:00
|
|
|
host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
|
|
|
|
traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
|
2016-03-24 17:35:27 +00:00
|
|
|
ipsec_sa_cfg_t *other_sa, policy_type_t type,
|
|
|
|
policy_priority_t priority, uint32_t manual_prio)
|
2011-07-28 12:24:42 +00:00
|
|
|
{
|
2017-02-28 13:44:38 +00:00
|
|
|
kernel_ipsec_policy_id_t in_id = {
|
2016-03-31 14:01:40 +00:00
|
|
|
.dir = POLICY_IN,
|
|
|
|
.src_ts = other_ts,
|
|
|
|
.dst_ts = my_ts,
|
|
|
|
.mark = this->mark_in,
|
|
|
|
};
|
2017-02-28 13:44:38 +00:00
|
|
|
kernel_ipsec_manage_policy_t in_policy = {
|
2016-03-31 14:01:40 +00:00
|
|
|
.type = type,
|
|
|
|
.prio = priority,
|
2016-03-24 17:35:27 +00:00
|
|
|
.manual_prio = manual_prio,
|
2016-03-31 14:01:40 +00:00
|
|
|
.src = other_addr,
|
|
|
|
.dst = my_addr,
|
|
|
|
.sa = my_sa,
|
|
|
|
};
|
2015-09-16 14:44:09 +00:00
|
|
|
|
2016-03-31 14:01:40 +00:00
|
|
|
charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
|
2017-02-28 13:44:38 +00:00
|
|
|
|
2011-07-28 12:24:42 +00:00
|
|
|
if (this->mode != MODE_TRANSPORT)
|
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
in_id.dir = POLICY_FWD;
|
|
|
|
charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
|
2017-02-28 13:44:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete outbound policies: out, [fwd]
|
|
|
|
*/
|
|
|
|
static void del_policies_outbound(private_child_sa_t *this,
|
|
|
|
host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
|
|
|
|
traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
|
|
|
|
ipsec_sa_cfg_t *other_sa, policy_type_t type,
|
|
|
|
policy_priority_t priority, uint32_t manual_prio)
|
|
|
|
{
|
|
|
|
kernel_ipsec_policy_id_t out_id = {
|
|
|
|
.dir = POLICY_OUT,
|
|
|
|
.src_ts = my_ts,
|
|
|
|
.dst_ts = other_ts,
|
|
|
|
.mark = this->mark_out,
|
|
|
|
.interface = this->config->get_interface(this->config),
|
|
|
|
};
|
|
|
|
kernel_ipsec_manage_policy_t out_policy = {
|
|
|
|
.type = type,
|
|
|
|
.prio = priority,
|
|
|
|
.manual_prio = manual_prio,
|
|
|
|
.src = my_addr,
|
|
|
|
.dst = other_addr,
|
|
|
|
.sa = other_sa,
|
|
|
|
};
|
|
|
|
|
|
|
|
charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
|
2016-04-01 14:41:05 +00:00
|
|
|
|
2017-02-28 13:44:38 +00:00
|
|
|
if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
|
|
|
|
{
|
|
|
|
out_id.dir = POLICY_FWD;
|
|
|
|
other_sa->reqid = 0;
|
|
|
|
if (priority == POLICY_PRIORITY_DEFAULT)
|
2016-05-02 12:21:30 +00:00
|
|
|
{
|
2017-02-28 13:44:38 +00:00
|
|
|
out_policy.prio = POLICY_PRIORITY_ROUTED;
|
2016-05-02 12:21:30 +00:00
|
|
|
}
|
2017-02-28 13:44:38 +00:00
|
|
|
charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
|
|
|
|
other_sa->reqid = this->reqid;
|
2011-07-28 12:24:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-28 13:44:38 +00:00
|
|
|
/**
|
|
|
|
* Delete in- and outbound policies
|
|
|
|
*/
|
|
|
|
static void del_policies_internal(private_child_sa_t *this,
|
|
|
|
host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
|
|
|
|
traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
|
|
|
|
ipsec_sa_cfg_t *other_sa, policy_type_t type,
|
|
|
|
policy_priority_t priority, uint32_t manual_prio)
|
|
|
|
{
|
|
|
|
del_policies_outbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
|
|
|
|
other_sa, type, priority, manual_prio);
|
|
|
|
del_policies_inbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
|
|
|
|
other_sa, type, priority, manual_prio);
|
|
|
|
}
|
|
|
|
|
2017-03-01 13:40:15 +00:00
|
|
|
METHOD(child_sa_t, set_policies, void,
|
2010-07-12 07:38:39 +00:00
|
|
|
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;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-03-01 13:40:15 +00:00
|
|
|
if (array_count(this->my_ts))
|
2014-10-21 09:36:18 +00:00
|
|
|
{
|
2017-03-01 13:40:15 +00:00
|
|
|
array_destroy_offset(this->my_ts,
|
|
|
|
offsetof(traffic_selector_t, destroy));
|
|
|
|
this->my_ts = array_create(0, 0);
|
2014-10-21 09:36:18 +00:00
|
|
|
}
|
2008-10-15 12:24:44 +00:00
|
|
|
enumerator = my_ts_list->create_enumerator(my_ts_list);
|
|
|
|
while (enumerator->enumerate(enumerator, &my_ts))
|
2006-02-22 16:14:40 +00:00
|
|
|
{
|
2013-07-17 08:08:19 +00:00
|
|
|
array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts));
|
2008-10-15 12:24:44 +00:00
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
2015-02-19 17:03:08 +00:00
|
|
|
array_sort(this->my_ts, (void*)traffic_selector_cmp, NULL);
|
|
|
|
|
2017-03-01 13:40:15 +00:00
|
|
|
if (array_count(this->other_ts))
|
|
|
|
{
|
|
|
|
array_destroy_offset(this->other_ts,
|
|
|
|
offsetof(traffic_selector_t, destroy));
|
|
|
|
this->other_ts = array_create(0, 0);
|
|
|
|
}
|
2008-10-15 12:24:44 +00:00
|
|
|
enumerator = other_ts_list->create_enumerator(other_ts_list);
|
|
|
|
while (enumerator->enumerate(enumerator, &other_ts))
|
|
|
|
{
|
2013-07-17 08:08:19 +00:00
|
|
|
array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts));
|
2008-10-15 12:24:44 +00:00
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
2015-02-19 17:03:08 +00:00
|
|
|
array_sort(this->other_ts, (void*)traffic_selector_cmp, NULL);
|
2017-03-01 13:40:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(child_sa_t, install_policies, status_t,
|
|
|
|
private_child_sa_t *this)
|
|
|
|
{
|
|
|
|
enumerator_t *enumerator;
|
|
|
|
linked_list_t *my_ts_list, *other_ts_list;
|
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
|
|
|
status_t status = SUCCESS;
|
|
|
|
|
|
|
|
if (!this->reqid_allocated && !this->static_reqid)
|
|
|
|
{
|
|
|
|
my_ts_list = linked_list_create_from_enumerator(
|
|
|
|
array_create_enumerator(this->my_ts));
|
|
|
|
other_ts_list = linked_list_create_from_enumerator(
|
|
|
|
array_create_enumerator(this->other_ts));
|
|
|
|
status = charon->kernel->alloc_reqid(
|
|
|
|
charon->kernel, my_ts_list, other_ts_list,
|
|
|
|
this->mark_in, this->mark_out, &this->reqid);
|
|
|
|
my_ts_list->destroy(my_ts_list);
|
|
|
|
other_ts_list->destroy(other_ts_list);
|
|
|
|
if (status != SUCCESS)
|
|
|
|
{
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
this->reqid_allocated = TRUE;
|
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-05-10 17:04:25 +00:00
|
|
|
if (!this->config->has_option(this->config, OPT_NO_POLICIES))
|
2008-10-15 12:24:44 +00:00
|
|
|
{
|
2011-07-27 11:41:35 +00:00
|
|
|
policy_priority_t priority;
|
2015-09-16 14:44:09 +00:00
|
|
|
ipsec_sa_cfg_t my_sa, other_sa;
|
2016-03-24 17:35:27 +00:00
|
|
|
uint32_t manual_prio;
|
2017-03-08 08:40:40 +00:00
|
|
|
bool install_outbound;
|
2015-09-16 14:44:09 +00:00
|
|
|
|
|
|
|
prepare_sa_cfg(this, &my_sa, &other_sa);
|
2016-03-24 17:35:27 +00:00
|
|
|
manual_prio = this->config->get_manual_prio(this->config);
|
2010-08-03 09:50:56 +00:00
|
|
|
|
2012-06-04 15:43:38 +00:00
|
|
|
/* if we're not in state CHILD_INSTALLING (i.e. if there is no SAD
|
|
|
|
* entry) we install a trap policy */
|
|
|
|
this->trap = this->state == CHILD_CREATED;
|
|
|
|
priority = this->trap ? POLICY_PRIORITY_ROUTED
|
|
|
|
: POLICY_PRIORITY_DEFAULT;
|
2017-03-21 14:08:14 +00:00
|
|
|
install_outbound = this->outbound_state != CHILD_OUTBOUND_REGISTERED;
|
2011-07-27 11:41:35 +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))
|
|
|
|
{
|
2011-07-27 11:44:33 +00:00
|
|
|
/* install outbound drop policy to avoid packets leaving unencrypted
|
|
|
|
* when updating policies */
|
2016-03-24 17:35:27 +00:00
|
|
|
if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 &&
|
2017-03-08 08:40:40 +00:00
|
|
|
require_policy_update() && install_outbound)
|
2011-07-27 11:44:33 +00:00
|
|
|
{
|
2017-02-28 13:44:38 +00:00
|
|
|
status |= install_policies_outbound(this, this->my_addr,
|
2011-07-28 12:24:42 +00:00
|
|
|
this->other_addr, my_ts, other_ts,
|
|
|
|
&my_sa, &other_sa, POLICY_DROP,
|
2016-03-24 17:35:27 +00:00
|
|
|
POLICY_PRIORITY_FALLBACK, 0);
|
2011-07-27 11:44:33 +00:00
|
|
|
}
|
|
|
|
|
2017-02-28 14:03:12 +00:00
|
|
|
status |= install_policies_inbound(this, this->my_addr,
|
2011-07-28 12:24:42 +00:00
|
|
|
this->other_addr, my_ts, other_ts,
|
2016-03-24 17:35:27 +00:00
|
|
|
&my_sa, &other_sa, POLICY_IPSEC,
|
|
|
|
priority, manual_prio);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2017-03-08 08:40:40 +00:00
|
|
|
if (install_outbound)
|
2017-02-28 14:03:12 +00:00
|
|
|
{
|
|
|
|
status |= install_policies_outbound(this, this->my_addr,
|
|
|
|
this->other_addr, my_ts, other_ts,
|
|
|
|
&my_sa, &other_sa, POLICY_IPSEC,
|
|
|
|
priority, manual_prio);
|
|
|
|
|
|
|
|
}
|
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
|
|
|
|
2012-06-04 15:43:38 +00:00
|
|
|
if (status == SUCCESS && this->trap)
|
|
|
|
{
|
2008-11-19 15:31:27 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-02-28 14:03:12 +00:00
|
|
|
METHOD(child_sa_t, register_outbound, void,
|
|
|
|
private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
|
|
|
|
uint16_t cpi, bool tfcv3)
|
|
|
|
{
|
|
|
|
DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names,
|
|
|
|
this->protocol);
|
|
|
|
DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr,
|
|
|
|
this->other_addr);
|
|
|
|
|
|
|
|
this->other_spi = spi;
|
|
|
|
this->other_cpi = cpi;
|
|
|
|
this->encr_r = chunk_clone(encr);
|
|
|
|
this->integ_r = chunk_clone(integ);
|
|
|
|
this->tfcv3 = tfcv3;
|
2017-03-21 14:08:14 +00:00
|
|
|
this->outbound_state = CHILD_OUTBOUND_REGISTERED;
|
2017-02-28 14:03:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(child_sa_t, install_outbound, status_t,
|
|
|
|
private_child_sa_t *this)
|
|
|
|
{
|
|
|
|
enumerator_t *enumerator;
|
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
status = install_internal(this, this->encr_r, this->integ_r,
|
|
|
|
this->other_spi, this->other_cpi, FALSE, FALSE,
|
|
|
|
this->tfcv3);
|
|
|
|
chunk_clear(&this->encr_r);
|
|
|
|
chunk_clear(&this->integ_r);
|
|
|
|
if (status != SUCCESS)
|
|
|
|
{
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
if (!this->config->has_option(this->config, OPT_NO_POLICIES))
|
|
|
|
{
|
|
|
|
ipsec_sa_cfg_t my_sa, other_sa;
|
|
|
|
uint32_t manual_prio;
|
|
|
|
|
|
|
|
prepare_sa_cfg(this, &my_sa, &other_sa);
|
|
|
|
manual_prio = this->config->get_manual_prio(this->config);
|
|
|
|
|
|
|
|
enumerator = create_policy_enumerator(this);
|
|
|
|
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
|
|
|
|
{
|
|
|
|
/* install outbound drop policy to avoid packets leaving unencrypted
|
|
|
|
* when updating policies */
|
|
|
|
if (manual_prio == 0 && require_policy_update())
|
|
|
|
{
|
|
|
|
status |= install_policies_outbound(this, this->my_addr,
|
|
|
|
this->other_addr, my_ts, other_ts,
|
|
|
|
&my_sa, &other_sa, POLICY_DROP,
|
|
|
|
POLICY_PRIORITY_FALLBACK, 0);
|
|
|
|
}
|
|
|
|
status |= install_policies_outbound(this, this->my_addr,
|
|
|
|
this->other_addr, my_ts, other_ts,
|
|
|
|
&my_sa, &other_sa, POLICY_IPSEC,
|
|
|
|
POLICY_PRIORITY_DEFAULT, manual_prio);
|
|
|
|
if (status != SUCCESS)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2017-03-20 12:35:56 +00:00
|
|
|
METHOD(child_sa_t, remove_outbound, void,
|
|
|
|
private_child_sa_t *this)
|
|
|
|
{
|
|
|
|
enumerator_t *enumerator;
|
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
|
|
|
|
|
|
|
switch (this->outbound_state)
|
|
|
|
{
|
2017-03-21 14:08:14 +00:00
|
|
|
case CHILD_OUTBOUND_INSTALLED:
|
2017-03-20 12:35:56 +00:00
|
|
|
break;
|
2017-03-21 14:08:14 +00:00
|
|
|
case CHILD_OUTBOUND_REGISTERED:
|
2017-03-20 12:35:56 +00:00
|
|
|
chunk_clear(&this->encr_r);
|
|
|
|
chunk_clear(&this->integ_r);
|
2017-03-21 14:08:14 +00:00
|
|
|
this->outbound_state = CHILD_OUTBOUND_NONE;
|
2017-03-20 12:35:56 +00:00
|
|
|
/* fall-through */
|
2017-03-21 14:08:14 +00:00
|
|
|
case CHILD_OUTBOUND_NONE:
|
2017-03-20 12:35:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this->config->has_option(this->config, OPT_NO_POLICIES))
|
|
|
|
{
|
|
|
|
ipsec_sa_cfg_t my_sa, other_sa;
|
|
|
|
uint32_t manual_prio;
|
|
|
|
|
|
|
|
prepare_sa_cfg(this, &my_sa, &other_sa);
|
|
|
|
manual_prio = this->config->get_manual_prio(this->config);
|
|
|
|
|
|
|
|
enumerator = create_policy_enumerator(this);
|
|
|
|
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
|
|
|
|
{
|
|
|
|
del_policies_outbound(this, this->my_addr, this->other_addr,
|
|
|
|
my_ts, other_ts, &my_sa, &other_sa,
|
|
|
|
POLICY_IPSEC, POLICY_PRIORITY_DEFAULT,
|
|
|
|
manual_prio);
|
|
|
|
if (manual_prio == 0 && require_policy_update())
|
|
|
|
{
|
|
|
|
del_policies_outbound(this, this->my_addr, this->other_addr,
|
|
|
|
my_ts, other_ts, &my_sa, &other_sa,
|
|
|
|
POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
|
|
|
}
|
|
|
|
|
|
|
|
kernel_ipsec_sa_id_t id = {
|
|
|
|
.src = this->my_addr,
|
|
|
|
.dst = this->other_addr,
|
|
|
|
.spi = this->other_spi,
|
|
|
|
.proto = proto_ike2ip(this->protocol),
|
|
|
|
.mark = this->mark_out,
|
|
|
|
};
|
|
|
|
kernel_ipsec_del_sa_t sa = {
|
|
|
|
.cpi = this->other_cpi,
|
|
|
|
};
|
|
|
|
charon->kernel->del_sa(charon->kernel, &id, &sa);
|
2017-03-21 14:08:14 +00:00
|
|
|
this->outbound_state = CHILD_OUTBOUND_NONE;
|
2017-03-20 12:35:56 +00:00
|
|
|
}
|
|
|
|
|
2017-02-28 14:03:45 +00:00
|
|
|
METHOD(child_sa_t, set_rekey_spi, void,
|
|
|
|
private_child_sa_t *this, uint32_t spi)
|
|
|
|
{
|
|
|
|
this->rekey_spi = spi;
|
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(child_sa_t, get_rekey_spi, uint32_t,
|
|
|
|
private_child_sa_t *this)
|
|
|
|
{
|
|
|
|
return this->rekey_spi;
|
|
|
|
}
|
|
|
|
|
2017-05-15 15:51:19 +00:00
|
|
|
CALLBACK(reinstall_vip, void,
|
|
|
|
host_t *vip, va_list args)
|
2012-08-21 11:50:32 +00:00
|
|
|
{
|
2017-05-15 15:51:19 +00:00
|
|
|
host_t *me;
|
2012-11-12 09:06:09 +00:00
|
|
|
char *iface;
|
|
|
|
|
2017-05-15 15:51:19 +00:00
|
|
|
VA_ARGS_VGET(args, me);
|
2016-02-12 14:30:18 +00:00
|
|
|
if (charon->kernel->get_interface(charon->kernel, me, &iface))
|
2012-11-12 09:06:09 +00:00
|
|
|
{
|
2016-02-12 14:30:18 +00:00
|
|
|
charon->kernel->del_ip(charon->kernel, vip, -1, TRUE);
|
|
|
|
charon->kernel->add_ip(charon->kernel, vip, -1, iface);
|
2012-11-12 09:06:09 +00:00
|
|
|
free(iface);
|
|
|
|
}
|
2012-08-21 11:50:32 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 07:38:39 +00:00
|
|
|
METHOD(child_sa_t, update, status_t,
|
2012-08-21 11:50:32 +00:00
|
|
|
private_child_sa_t *this, host_t *me, host_t *other, linked_list_t *vips,
|
|
|
|
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);
|
2017-05-10 17:04:25 +00:00
|
|
|
transport_proxy_mode = this->mode == MODE_TRANSPORT &&
|
|
|
|
this->config->has_option(this->config,
|
|
|
|
OPT_PROXY_MODE);
|
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
|
|
|
{
|
2011-08-15 14:31:04 +00:00
|
|
|
/* update our (initiator) SA */
|
2008-11-16 21:19:58 +00:00
|
|
|
if (this->my_spi)
|
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_sa_id_t id = {
|
|
|
|
.src = this->other_addr,
|
|
|
|
.dst = this->my_addr,
|
|
|
|
.spi = this->my_spi,
|
|
|
|
.proto = proto_ike2ip(this->protocol),
|
|
|
|
};
|
|
|
|
kernel_ipsec_update_sa_t sa = {
|
|
|
|
.cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
|
|
|
|
.new_src = other,
|
|
|
|
.new_dst = me,
|
|
|
|
.encap = this->encap,
|
|
|
|
.new_encap = encap,
|
|
|
|
};
|
|
|
|
if (charon->kernel->update_sa(charon->kernel, &id,
|
|
|
|
&sa) == NOT_SUPPORTED)
|
2008-11-16 21:19:58 +00:00
|
|
|
{
|
2014-05-09 06:39:55 +00:00
|
|
|
set_state(this, old);
|
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)
|
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_sa_id_t id = {
|
|
|
|
.src = this->my_addr,
|
|
|
|
.dst = this->other_addr,
|
|
|
|
.spi = this->other_spi,
|
|
|
|
.proto = proto_ike2ip(this->protocol),
|
|
|
|
.mark = this->mark_out,
|
|
|
|
};
|
|
|
|
kernel_ipsec_update_sa_t sa = {
|
|
|
|
.cpi = this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
|
|
|
|
.new_src = me,
|
|
|
|
.new_dst = other,
|
|
|
|
.encap = this->encap,
|
|
|
|
.new_encap = encap,
|
|
|
|
};
|
|
|
|
if (charon->kernel->update_sa(charon->kernel, &id,
|
|
|
|
&sa) == NOT_SUPPORTED)
|
2008-11-16 21:19:58 +00:00
|
|
|
{
|
2014-05-09 06:39:55 +00:00
|
|
|
set_state(this, old);
|
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
|
|
|
|
2017-05-10 17:04:25 +00:00
|
|
|
if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
|
|
|
|
require_policy_update())
|
2006-06-22 06:36:28 +00:00
|
|
|
{
|
2008-11-11 06:37:37 +00:00
|
|
|
if (!me->ip_equals(me, this->my_addr) ||
|
|
|
|
!other->ip_equals(other, this->other_addr))
|
2006-06-22 06:36:28 +00:00
|
|
|
{
|
2015-09-16 14:44:09 +00:00
|
|
|
ipsec_sa_cfg_t my_sa, other_sa;
|
2008-11-11 06:37:37 +00:00
|
|
|
enumerator_t *enumerator;
|
|
|
|
traffic_selector_t *my_ts, *other_ts;
|
2016-03-24 17:35:27 +00:00
|
|
|
uint32_t manual_prio;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2015-09-16 14:44:09 +00:00
|
|
|
prepare_sa_cfg(this, &my_sa, &other_sa);
|
2016-03-24 17:35:27 +00:00
|
|
|
manual_prio = this->config->get_manual_prio(this->config);
|
2015-09-16 14:44: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))
|
|
|
|
{
|
2011-07-29 10:34:51 +00:00
|
|
|
traffic_selector_t *old_my_ts = NULL, *old_other_ts = NULL;
|
2016-03-24 17:35:27 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
/* remove old policies first */
|
2015-09-16 14:44:09 +00:00
|
|
|
del_policies_internal(this, this->my_addr, this->other_addr,
|
2016-03-24 17:35:27 +00:00
|
|
|
my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC,
|
|
|
|
POLICY_PRIORITY_DEFAULT, manual_prio);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2011-07-28 12:24:42 +00:00
|
|
|
/* check if we have to update a "dynamic" traffic selector */
|
2008-11-11 06:37:37 +00:00
|
|
|
if (!me->ip_equals(me, this->my_addr) &&
|
|
|
|
my_ts->is_host(my_ts, this->my_addr))
|
|
|
|
{
|
2011-07-29 10:34:51 +00:00
|
|
|
old_my_ts = my_ts->clone(my_ts);
|
2008-11-11 06:37:37 +00:00
|
|
|
my_ts->set_address(my_ts, me);
|
|
|
|
}
|
|
|
|
if (!other->ip_equals(other, this->other_addr) &&
|
|
|
|
other_ts->is_host(other_ts, this->other_addr))
|
|
|
|
{
|
2011-07-29 10:34:51 +00:00
|
|
|
old_other_ts = other_ts->clone(other_ts);
|
2008-11-11 06:37:37 +00:00
|
|
|
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 */
|
2017-05-15 15:51:19 +00:00
|
|
|
vips->invoke_function(vips, reinstall_vip, me);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2008-11-11 06:37:37 +00:00
|
|
|
/* reinstall updated policies */
|
2011-07-28 12:24:42 +00:00
|
|
|
install_policies_internal(this, me, other, my_ts, other_ts,
|
2015-09-16 14:44:09 +00:00
|
|
|
&my_sa, &other_sa, POLICY_IPSEC,
|
2016-03-24 17:35:27 +00:00
|
|
|
POLICY_PRIORITY_DEFAULT, manual_prio);
|
2011-07-29 10:34:51 +00:00
|
|
|
|
|
|
|
/* update fallback policies after the new policy is in place */
|
2016-03-24 17:35:27 +00:00
|
|
|
if (manual_prio == 0)
|
|
|
|
{
|
2017-02-28 13:44:38 +00:00
|
|
|
del_policies_outbound(this, this->my_addr, this->other_addr,
|
2016-03-24 17:35:27 +00:00
|
|
|
old_my_ts ?: my_ts,
|
|
|
|
old_other_ts ?: other_ts,
|
|
|
|
&my_sa, &other_sa, POLICY_DROP,
|
|
|
|
POLICY_PRIORITY_FALLBACK, 0);
|
2017-02-28 13:44:38 +00:00
|
|
|
install_policies_outbound(this, me, other, my_ts, other_ts,
|
2015-09-16 14:44:09 +00:00
|
|
|
&my_sa, &other_sa, POLICY_DROP,
|
2016-03-24 17:35:27 +00:00
|
|
|
POLICY_PRIORITY_FALLBACK, 0);
|
|
|
|
}
|
2015-09-16 14:44:09 +00:00
|
|
|
DESTROY_IF(old_my_ts);
|
|
|
|
DESTROY_IF(old_other_ts);
|
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;
|
2011-07-27 11:41:35 +00:00
|
|
|
policy_priority_t priority;
|
|
|
|
|
2012-06-04 15:43:38 +00:00
|
|
|
priority = this->trap ? POLICY_PRIORITY_ROUTED : POLICY_PRIORITY_DEFAULT;
|
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
|
|
|
|
2017-05-10 17:04:25 +00:00
|
|
|
if (!this->config->has_option(this->config, OPT_NO_POLICIES))
|
2006-06-09 15:12:43 +00:00
|
|
|
{
|
2015-09-16 14:44:09 +00:00
|
|
|
ipsec_sa_cfg_t my_sa, other_sa;
|
2016-03-24 17:35:27 +00:00
|
|
|
uint32_t manual_prio;
|
2017-03-20 12:35:56 +00:00
|
|
|
bool del_outbound;
|
2015-09-16 14:44:09 +00:00
|
|
|
|
|
|
|
prepare_sa_cfg(this, &my_sa, &other_sa);
|
2016-03-24 17:35:27 +00:00
|
|
|
manual_prio = this->config->get_manual_prio(this->config);
|
2017-03-21 14:08:14 +00:00
|
|
|
del_outbound = this->trap ||
|
|
|
|
this->outbound_state == CHILD_OUTBOUND_INSTALLED;
|
2015-09-16 14:44:09 +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))
|
|
|
|
{
|
2017-03-20 12:35:56 +00:00
|
|
|
if (del_outbound)
|
|
|
|
{
|
|
|
|
del_policies_outbound(this, this->my_addr,
|
|
|
|
this->other_addr, my_ts, other_ts,
|
|
|
|
&my_sa, &other_sa, POLICY_IPSEC,
|
|
|
|
priority, manual_prio);
|
|
|
|
}
|
|
|
|
del_policies_inbound(this, this->my_addr, this->other_addr,
|
|
|
|
my_ts, other_ts, &my_sa, &other_sa,
|
|
|
|
POLICY_IPSEC, priority, manual_prio);
|
|
|
|
if (!this->trap && manual_prio == 0 && require_policy_update() &&
|
|
|
|
del_outbound)
|
2011-07-27 11:44:33 +00:00
|
|
|
{
|
2017-02-28 13:44:38 +00:00
|
|
|
del_policies_outbound(this, this->my_addr, this->other_addr,
|
2016-03-24 17:35:27 +00:00
|
|
|
my_ts, other_ts, &my_sa, &other_sa,
|
|
|
|
POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0);
|
2011-07-27 11:44:33 +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
|
|
|
|
2015-03-17 08:58:00 +00:00
|
|
|
/* delete SAs in the kernel, if they are set up */
|
|
|
|
if (this->my_spi)
|
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_sa_id_t id = {
|
|
|
|
.src = this->other_addr,
|
|
|
|
.dst = this->my_addr,
|
|
|
|
.spi = this->my_spi,
|
|
|
|
.proto = proto_ike2ip(this->protocol),
|
|
|
|
};
|
|
|
|
kernel_ipsec_del_sa_t sa = {
|
|
|
|
.cpi = this->my_cpi,
|
|
|
|
};
|
|
|
|
charon->kernel->del_sa(charon->kernel, &id, &sa);
|
2015-03-17 08:58:00 +00:00
|
|
|
}
|
2017-03-21 14:08:14 +00:00
|
|
|
if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED)
|
2015-03-17 08:58:00 +00:00
|
|
|
{
|
2016-03-31 14:01:40 +00:00
|
|
|
kernel_ipsec_sa_id_t id = {
|
|
|
|
.src = this->my_addr,
|
|
|
|
.dst = this->other_addr,
|
|
|
|
.spi = this->other_spi,
|
|
|
|
.proto = proto_ike2ip(this->protocol),
|
|
|
|
.mark = this->mark_out,
|
|
|
|
};
|
|
|
|
kernel_ipsec_del_sa_t sa = {
|
|
|
|
.cpi = this->other_cpi,
|
|
|
|
};
|
|
|
|
charon->kernel->del_sa(charon->kernel, &id, &sa);
|
2015-03-17 08:58:00 +00:00
|
|
|
}
|
|
|
|
|
2014-10-21 09:36:18 +00:00
|
|
|
if (this->reqid_allocated)
|
|
|
|
{
|
2016-02-12 14:30:18 +00:00
|
|
|
if (charon->kernel->release_reqid(charon->kernel,
|
2014-10-21 09:36:18 +00:00
|
|
|
this->reqid, this->mark_in, this->mark_out) != SUCCESS)
|
|
|
|
{
|
|
|
|
DBG1(DBG_CHD, "releasing reqid %u failed", this->reqid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-17 08:08:19 +00:00
|
|
|
array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
|
|
|
|
array_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);
|
2017-02-28 14:03:12 +00:00
|
|
|
chunk_clear(&this->encr_r);
|
|
|
|
chunk_clear(&this->integ_r);
|
2006-04-10 08:07:38 +00:00
|
|
|
free(this);
|
2006-02-16 09:55:07 +00:00
|
|
|
}
|
|
|
|
|
2013-07-17 08:28:45 +00:00
|
|
|
/**
|
|
|
|
* Get proxy address for one side, if any
|
|
|
|
*/
|
|
|
|
static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
|
|
|
|
{
|
|
|
|
host_t *host = NULL;
|
2016-03-22 12:22:01 +00:00
|
|
|
uint8_t mask;
|
2013-07-17 08:28:45 +00:00
|
|
|
enumerator_t *enumerator;
|
|
|
|
linked_list_t *ts_list, *list;
|
|
|
|
traffic_selector_t *ts;
|
|
|
|
|
|
|
|
list = linked_list_create_with_items(ike, NULL);
|
|
|
|
ts_list = config->get_traffic_selectors(config, local, NULL, list);
|
|
|
|
list->destroy(list);
|
|
|
|
|
|
|
|
enumerator = ts_list->create_enumerator(ts_list);
|
|
|
|
while (enumerator->enumerate(enumerator, &ts))
|
|
|
|
{
|
|
|
|
if (ts->is_host(ts, NULL) && ts->to_subnet(ts, &host, &mask))
|
|
|
|
{
|
|
|
|
DBG1(DBG_CHD, "%s address: %H is a transport mode proxy for %H",
|
|
|
|
local ? "my" : "other", ike, host);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
|
|
|
ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
|
|
|
|
|
|
|
|
if (!host)
|
|
|
|
{
|
|
|
|
host = ike->clone(ike);
|
|
|
|
}
|
|
|
|
return host;
|
|
|
|
}
|
|
|
|
|
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,
|
2016-03-22 12:22:01 +00:00
|
|
|
child_cfg_t *config, uint32_t rekey, bool encap,
|
2014-11-13 14:26:10 +00:00
|
|
|
u_int mark_in, u_int mark_out)
|
2006-02-16 09:55:07 +00:00
|
|
|
{
|
2010-07-12 07:38:39 +00:00
|
|
|
private_child_sa_t *this;
|
2016-05-19 09:56:44 +00:00
|
|
|
static refcount_t unique_id = 0, unique_mark = 0;
|
|
|
|
refcount_t mark;
|
2010-07-12 07:38:39 +00:00
|
|
|
|
|
|
|
INIT(this,
|
|
|
|
.public = {
|
|
|
|
.get_name = _get_name,
|
|
|
|
.get_reqid = _get_reqid,
|
2014-10-23 09:27:25 +00:00
|
|
|
.get_unique_id = _get_unique_id,
|
2010-07-12 07:38:39 +00:00
|
|
|
.get_config = _get_config,
|
|
|
|
.get_state = _get_state,
|
|
|
|
.set_state = _set_state,
|
2017-03-21 14:08:14 +00:00
|
|
|
.get_outbound_state = _get_outbound_state,
|
2010-07-12 07:38:39 +00:00
|
|
|
.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,
|
2013-11-07 08:20:40 +00:00
|
|
|
.get_installtime = _get_installtime,
|
2010-07-12 07:38:39 +00:00
|
|
|
.get_usestats = _get_usestats,
|
2012-03-21 15:54:24 +00:00
|
|
|
.get_mark = _get_mark,
|
2010-07-12 07:38:39 +00:00
|
|
|
.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,
|
2017-02-28 14:03:12 +00:00
|
|
|
.register_outbound = _register_outbound,
|
|
|
|
.install_outbound = _install_outbound,
|
2017-03-20 12:35:56 +00:00
|
|
|
.remove_outbound = _remove_outbound,
|
2017-02-28 14:03:45 +00:00
|
|
|
.set_rekey_spi = _set_rekey_spi,
|
|
|
|
.get_rekey_spi = _get_rekey_spi,
|
2010-07-12 07:38:39 +00:00
|
|
|
.update = _update,
|
2017-03-01 13:40:15 +00:00
|
|
|
.set_policies = _set_policies,
|
|
|
|
.install_policies = _install_policies,
|
2013-07-17 08:01:22 +00:00
|
|
|
.create_ts_enumerator = _create_ts_enumerator,
|
2010-07-12 07:38:39 +00:00
|
|
|
.create_policy_enumerator = _create_policy_enumerator,
|
|
|
|
.destroy = _destroy,
|
|
|
|
},
|
|
|
|
.encap = encap,
|
|
|
|
.ipcomp = IPCOMP_NONE,
|
|
|
|
.state = CHILD_CREATED,
|
2013-07-17 08:08:19 +00:00
|
|
|
.my_ts = array_create(0, 0),
|
|
|
|
.other_ts = array_create(0, 0),
|
2010-07-12 07:38:39 +00:00
|
|
|
.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),
|
2014-10-23 09:27:25 +00:00
|
|
|
.unique_id = ref_get(&unique_id),
|
2010-07-12 07:38:39 +00:00
|
|
|
.mark_in = config->get_mark(config, TRUE),
|
|
|
|
.mark_out = config->get_mark(config, FALSE),
|
2013-11-07 08:20:40 +00:00
|
|
|
.install_time = time_monotonic(NULL),
|
2017-05-10 17:04:25 +00:00
|
|
|
.policies_fwd_out = config->has_option(config, OPT_FWD_OUT_POLICIES),
|
2010-07-12 07:38:39 +00:00
|
|
|
);
|
|
|
|
|
2007-04-10 06:01:03 +00:00
|
|
|
this->config = config;
|
|
|
|
config->get_ref(config);
|
2010-07-02 21:45:57 +00:00
|
|
|
|
2014-11-13 14:26:10 +00:00
|
|
|
if (mark_in)
|
|
|
|
{
|
|
|
|
this->mark_in.value = mark_in;
|
|
|
|
}
|
|
|
|
if (mark_out)
|
|
|
|
{
|
|
|
|
this->mark_out.value = mark_out;
|
|
|
|
}
|
|
|
|
if (this->mark_in.value == MARK_UNIQUE ||
|
|
|
|
this->mark_out.value == MARK_UNIQUE)
|
|
|
|
{
|
|
|
|
mark = ref_get(&unique_mark);
|
|
|
|
if (this->mark_in.value == MARK_UNIQUE)
|
|
|
|
{
|
|
|
|
this->mark_in.value = mark;
|
|
|
|
}
|
|
|
|
if (this->mark_out.value == MARK_UNIQUE)
|
|
|
|
{
|
|
|
|
this->mark_out.value = mark;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-22 15:03:30 +00:00
|
|
|
if (!this->reqid)
|
|
|
|
{
|
2014-10-21 09:36:18 +00:00
|
|
|
/* reuse old reqid if we are rekeying an existing CHILD_SA. While the
|
|
|
|
* reqid cache would find the same reqid for our selectors, this does
|
|
|
|
* not work in a special case: If an SA is triggered by a trap policy,
|
|
|
|
* but the negotiated SA gets narrowed, we still must reuse the same
|
2015-03-25 09:59:36 +00:00
|
|
|
* reqid to successfully "trigger" the SA on the kernel level. Rekeying
|
2014-10-21 09:36:18 +00:00
|
|
|
* such an SA requires an explicit reqid, as the cache currently knows
|
|
|
|
* the original selectors only for that reqid. */
|
2013-05-08 13:18:50 +00:00
|
|
|
if (rekey)
|
|
|
|
{
|
|
|
|
this->reqid = rekey;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-11 14:11:14 +00:00
|
|
|
this->reqid = charon->traps->find_reqid(charon->traps, config);
|
2013-05-08 13:18:50 +00:00
|
|
|
}
|
2010-04-22 15:03:30 +00:00
|
|
|
}
|
2015-07-31 14:51:35 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
this->static_reqid = TRUE;
|
|
|
|
}
|
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 &&
|
2017-05-10 17:04:25 +00:00
|
|
|
config->has_option(config, OPT_PROXY_MODE))
|
2008-11-11 06:37:37 +00:00
|
|
|
{
|
|
|
|
this->mode = MODE_TRANSPORT;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2013-07-17 08:28:45 +00:00
|
|
|
this->my_addr = get_proxy_addr(config, me, TRUE);
|
|
|
|
this->other_addr = get_proxy_addr(config, other, FALSE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->my_addr = me->clone(me);
|
|
|
|
this->other_addr = other->clone(other);
|
2008-11-11 06:37:37 +00:00
|
|
|
}
|
2006-06-22 06:36:28 +00:00
|
|
|
return &this->public;
|
2005-12-04 19:05:52 +00:00
|
|
|
}
|