Use a sync message cache to resynchronize IKE_SAs without rekeying
[strongswan.git] / src / libcharon / plugins / ha / ha_child.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "ha_child.h"
17
18 typedef struct private_ha_child_t private_ha_child_t;
19
20 /**
21 * Private data of an ha_child_t object.
22 */
23 struct private_ha_child_t {
24
25 /**
26 * Public ha_child_t interface.
27 */
28 ha_child_t public;
29
30 /**
31 * socket we use for syncing
32 */
33 ha_socket_t *socket;
34
35 /**
36 * tunnel securing sync messages
37 */
38 ha_tunnel_t *tunnel;
39
40 /**
41 * message cache
42 */
43 ha_cache_t *cache;
44 };
45
46 METHOD(listener_t, child_keys, bool,
47 private_ha_child_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
48 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
49 {
50 ha_message_t *m;
51 chunk_t secret;
52 proposal_t *proposal;
53 u_int16_t alg, len;
54 linked_list_t *list;
55 enumerator_t *enumerator;
56 traffic_selector_t *ts;
57
58 if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
59 { /* do not sync SA between nodes */
60 return TRUE;
61 }
62
63 m = ha_message_create(HA_CHILD_ADD);
64
65 m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
66 m->add_attribute(m, HA_INBOUND_SPI, child_sa->get_spi(child_sa, TRUE));
67 m->add_attribute(m, HA_OUTBOUND_SPI, child_sa->get_spi(child_sa, FALSE));
68 m->add_attribute(m, HA_INBOUND_CPI, child_sa->get_cpi(child_sa, TRUE));
69 m->add_attribute(m, HA_OUTBOUND_CPI, child_sa->get_cpi(child_sa, FALSE));
70 m->add_attribute(m, HA_IPSEC_MODE, child_sa->get_mode(child_sa));
71 m->add_attribute(m, HA_IPCOMP, child_sa->get_ipcomp(child_sa));
72 m->add_attribute(m, HA_CONFIG_NAME, child_sa->get_name(child_sa));
73
74 proposal = child_sa->get_proposal(child_sa);
75 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len))
76 {
77 m->add_attribute(m, HA_ALG_ENCR, alg);
78 if (len)
79 {
80 m->add_attribute(m, HA_ALG_ENCR_LEN, len);
81 }
82 }
83 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
84 {
85 m->add_attribute(m, HA_ALG_INTEG, alg);
86 }
87 m->add_attribute(m, HA_NONCE_I, nonce_i);
88 m->add_attribute(m, HA_NONCE_R, nonce_r);
89 if (dh && dh->get_shared_secret(dh, &secret) == SUCCESS)
90 {
91 m->add_attribute(m, HA_SECRET, secret);
92 chunk_clear(&secret);
93 }
94
95 list = child_sa->get_traffic_selectors(child_sa, TRUE);
96 enumerator = list->create_enumerator(list);
97 while (enumerator->enumerate(enumerator, &ts))
98 {
99 m->add_attribute(m, HA_LOCAL_TS, ts);
100 }
101 enumerator->destroy(enumerator);
102 list = child_sa->get_traffic_selectors(child_sa, FALSE);
103 enumerator = list->create_enumerator(list);
104 while (enumerator->enumerate(enumerator, &ts))
105 {
106 m->add_attribute(m, HA_REMOTE_TS, ts);
107 }
108 enumerator->destroy(enumerator);
109
110 this->socket->push(this->socket, m);
111 m->destroy(m);
112
113 return TRUE;
114 }
115
116 METHOD(listener_t, child_state_change, bool,
117 private_ha_child_t *this, ike_sa_t *ike_sa,
118 child_sa_t *child_sa, child_sa_state_t state)
119 {
120 if (!ike_sa ||
121 ike_sa->get_state(ike_sa) == IKE_PASSIVE ||
122 ike_sa->get_state(ike_sa) == IKE_DESTROYING)
123 { /* only sync active IKE_SAs */
124 return TRUE;
125 }
126 if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
127 { /* do not sync SA between nodes */
128 return TRUE;
129 }
130
131
132 if (state == CHILD_DESTROYING)
133 {
134 ha_message_t *m;
135
136 m = ha_message_create(HA_CHILD_DELETE);
137
138 m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
139 m->add_attribute(m, HA_INBOUND_SPI,
140 child_sa->get_spi(child_sa, TRUE));
141 this->socket->push(this->socket, m);
142 m->destroy(m);
143 }
144 return TRUE;
145 }
146
147 METHOD(ha_child_t, destroy, void,
148 private_ha_child_t *this)
149 {
150 free(this);
151 }
152
153 /**
154 * See header
155 */
156 ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
157 ha_cache_t *cache)
158 {
159 private_ha_child_t *this;
160
161 INIT(this,
162 .public = {
163 .listener = {
164 .child_keys = _child_keys,
165 .child_state_change = _child_state_change,
166 },
167 .destroy = _destroy,
168 },
169 .socket = socket,
170 .tunnel = tunnel,
171 .cache = cache,
172 );
173
174 return &this->public;
175 }
176