kernel-interface: Pass the same data to del_policy() that was passed to add_policy()
[strongswan.git] / src / charon-tkm / src / tkm / tkm_kernel_ipsec.c
1 /*
2 * Copyright (C) 2012-2014 Reto Buerki
3 * Copyright (C) 2012 Adrian-Ken Rueegsegger
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <errno.h>
18 #include <netinet/udp.h>
19 #include <linux/xfrm.h>
20 #include <utils/debug.h>
21 #include <utils/chunk.h>
22 #include <tkm/constants.h>
23 #include <tkm/client.h>
24
25 #include "tkm.h"
26 #include "tkm_utils.h"
27 #include "tkm_types.h"
28 #include "tkm_keymat.h"
29 #include "tkm_kernel_ipsec.h"
30
31 /** From linux/in.h */
32 #ifndef IP_XFRM_POLICY
33 #define IP_XFRM_POLICY 17
34 #endif
35
36 typedef struct private_tkm_kernel_ipsec_t private_tkm_kernel_ipsec_t;
37
38 /**
39 * Private variables and functions of TKM kernel ipsec instance.
40 */
41 struct private_tkm_kernel_ipsec_t {
42
43 /**
44 * Public tkm_kernel_ipsec interface.
45 */
46 tkm_kernel_ipsec_t public;
47
48 /**
49 * RNG used for SPI generation.
50 */
51 rng_t *rng;
52
53 };
54
55 METHOD(kernel_ipsec_t, get_spi, status_t,
56 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
57 u_int8_t protocol, u_int32_t *spi)
58 {
59 bool result;
60
61 if (!this->rng)
62 {
63 this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
64 if (!this->rng)
65 {
66 DBG1(DBG_KNL, "unable to create RNG");
67 return FAILED;
68 }
69 }
70
71 result = this->rng->get_bytes(this->rng, sizeof(u_int32_t),
72 (u_int8_t *)spi);
73 return result ? SUCCESS : FAILED;
74 }
75
76 METHOD(kernel_ipsec_t, get_cpi, status_t,
77 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
78 u_int16_t *cpi)
79 {
80 return NOT_SUPPORTED;
81 }
82
83 METHOD(kernel_ipsec_t, add_sa, status_t,
84 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
85 u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
86 u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
87 u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
88 u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window,
89 bool initiator, bool encap, bool esn, bool inbound, bool update,
90 linked_list_t* src_ts, linked_list_t* dst_ts)
91 {
92 esa_info_t esa;
93 esp_spi_type spi_loc, spi_rem;
94 host_t *local, *peer;
95 chunk_t *nonce_loc, *nonce_rem;
96 nc_id_type nonce_loc_id;
97 esa_id_type esa_id;
98 nonce_type nc_rem;
99
100 if (enc_key.ptr == NULL)
101 {
102 DBG1(DBG_KNL, "Unable to get ESA information");
103 return FAILED;
104 }
105 esa = *(esa_info_t *)(enc_key.ptr);
106
107 /* only handle the case where we have both distinct ESP spi's available */
108 if (esa.spi_r == spi)
109 {
110 chunk_free(&esa.nonce_i);
111 chunk_free(&esa.nonce_r);
112 return SUCCESS;
113 }
114
115 if (initiator)
116 {
117 spi_loc = spi;
118 spi_rem = esa.spi_r;
119 local = dst;
120 peer = src;
121 nonce_loc = &esa.nonce_i;
122 nonce_rem = &esa.nonce_r;
123 }
124 else
125 {
126 spi_loc = esa.spi_r;
127 spi_rem = spi;
128 local = src;
129 peer = dst;
130 nonce_loc = &esa.nonce_r;
131 nonce_rem = &esa.nonce_i;
132 }
133
134 esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA);
135 if (!tkm->sad->insert(tkm->sad, esa_id, reqid, local, peer, spi_loc, spi_rem,
136 protocol))
137 {
138 DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id);
139 goto sad_failure;
140 }
141
142 /*
143 * creation of first CHILD SA:
144 * no nonce and no dh contexts because the ones from the IKE SA are re-used
145 */
146 nonce_loc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce_loc);
147 if (nonce_loc_id == 0 && esa.dh_id == 0)
148 {
149 if (ike_esa_create_first(esa_id, esa.isa_id, reqid, 1, spi_loc, spi_rem)
150 != TKM_OK)
151 {
152 DBG1(DBG_KNL, "child SA (%llu, first) creation failed", esa_id);
153 goto failure;
154 }
155 }
156 /* creation of child SA without PFS: no dh context */
157 else if (nonce_loc_id != 0 && esa.dh_id == 0)
158 {
159 chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type));
160 if (ike_esa_create_no_pfs(esa_id, esa.isa_id, reqid, 1, nonce_loc_id,
161 nc_rem, initiator, spi_loc, spi_rem)
162 != TKM_OK)
163 {
164 DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id);
165 goto failure;
166 }
167 tkm->chunk_map->remove(tkm->chunk_map, nonce_loc);
168 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id);
169 }
170 /* creation of subsequent child SA with PFS: nonce and dh context are set */
171 else
172 {
173 chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type));
174 if (ike_esa_create(esa_id, esa.isa_id, reqid, 1, esa.dh_id, nonce_loc_id,
175 nc_rem, initiator, spi_loc, spi_rem) != TKM_OK)
176 {
177 DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id);
178 goto failure;
179 }
180 tkm->chunk_map->remove(tkm->chunk_map, nonce_loc);
181 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id);
182 }
183 if (ike_esa_select(esa_id) != TKM_OK)
184 {
185 DBG1(DBG_KNL, "error selecting new child SA (%llu)", esa_id);
186 if (ike_esa_reset(esa_id) != TKM_OK)
187 {
188 DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id);
189 }
190 goto failure;
191 }
192
193 DBG1(DBG_KNL, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, "
194 "esp_spi_rem: %x, role: %s)", esa_id, esa.isa_id, ntohl(spi_loc),
195 ntohl(spi_rem), initiator ? "initiator" : "responder");
196 chunk_free(&esa.nonce_i);
197 chunk_free(&esa.nonce_r);
198
199 return SUCCESS;
200
201 failure:
202 tkm->sad->remove(tkm->sad, esa_id);
203 sad_failure:
204 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
205 chunk_free(&esa.nonce_i);
206 chunk_free(&esa.nonce_r);
207 return FAILED;
208 }
209
210 METHOD(kernel_ipsec_t, query_sa, status_t,
211 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
212 u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes,
213 u_int64_t *packets, time_t *time)
214 {
215 return NOT_SUPPORTED;
216 }
217
218 METHOD(kernel_ipsec_t, del_sa, status_t,
219 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
220 u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark)
221 {
222 esa_id_type esa_id, other_esa_id;
223
224 esa_id = tkm->sad->get_esa_id(tkm->sad, src, dst, spi, protocol);
225 if (esa_id)
226 {
227 other_esa_id = tkm->sad->get_other_esa_id(tkm->sad, esa_id);
228 if (other_esa_id)
229 {
230 DBG1(DBG_KNL, "selecting child SA (esa: %llu)", other_esa_id);
231 if (ike_esa_select(other_esa_id) != TKM_OK)
232 {
233 DBG1(DBG_KNL, "error selecting other child SA (esa: %llu)",
234 other_esa_id);
235 }
236 }
237
238 DBG1(DBG_KNL, "deleting child SA (esa: %llu, spi: %x)", esa_id,
239 ntohl(spi));
240 if (ike_esa_reset(esa_id) != TKM_OK)
241 {
242 DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id);
243 return FAILED;
244 }
245 tkm->sad->remove(tkm->sad, esa_id);
246 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
247 }
248 return SUCCESS;
249 }
250
251 METHOD(kernel_ipsec_t, update_sa, status_t,
252 private_tkm_kernel_ipsec_t *this, u_int32_t spi, u_int8_t protocol,
253 u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
254 bool old_encap, bool new_encap, mark_t mark)
255 {
256 return NOT_SUPPORTED;
257 }
258
259 METHOD(kernel_ipsec_t, flush_sas, status_t,
260 private_tkm_kernel_ipsec_t *this)
261 {
262 DBG1(DBG_KNL, "flushing child SA entries");
263 return SUCCESS;
264 }
265
266 METHOD(kernel_ipsec_t, add_policy, status_t,
267 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
268 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
269 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
270 mark_t mark, policy_priority_t priority)
271 {
272 return SUCCESS;
273 }
274
275 METHOD(kernel_ipsec_t, query_policy, status_t,
276 private_tkm_kernel_ipsec_t *this, traffic_selector_t *src_ts,
277 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
278 time_t *use_time)
279 {
280 return NOT_SUPPORTED;
281 }
282
283 METHOD(kernel_ipsec_t, del_policy, status_t,
284 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
285 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
286 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
287 mark_t mark, policy_priority_t priority)
288 {
289 return SUCCESS;
290 }
291
292 METHOD(kernel_ipsec_t, flush_policies, status_t,
293 private_tkm_kernel_ipsec_t *this)
294 {
295 return SUCCESS;
296 }
297
298
299 METHOD(kernel_ipsec_t, bypass_socket, bool,
300 private_tkm_kernel_ipsec_t *this, int fd, int family)
301 {
302 struct xfrm_userpolicy_info policy;
303 u_int sol, ipsec_policy;
304
305 switch (family)
306 {
307 case AF_INET:
308 sol = SOL_IP;
309 ipsec_policy = IP_XFRM_POLICY;
310 break;
311 case AF_INET6:
312 sol = SOL_IPV6;
313 ipsec_policy = IPV6_XFRM_POLICY;
314 break;
315 default:
316 return FALSE;
317 }
318
319 memset(&policy, 0, sizeof(policy));
320 policy.action = XFRM_POLICY_ALLOW;
321 policy.sel.family = family;
322
323 policy.dir = XFRM_POLICY_OUT;
324 if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
325 {
326 DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
327 strerror(errno));
328 return FALSE;
329 }
330 policy.dir = XFRM_POLICY_IN;
331 if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
332 {
333 DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
334 strerror(errno));
335 return FALSE;
336 }
337 return TRUE;
338 }
339
340 METHOD(kernel_ipsec_t, enable_udp_decap, bool,
341 private_tkm_kernel_ipsec_t *this, int fd, int family, u_int16_t port)
342 {
343 int type = UDP_ENCAP_ESPINUDP;
344
345 if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
346 {
347 DBG1(DBG_KNL, "unable to set UDP_ENCAP: %s", strerror(errno));
348 return FALSE;
349 }
350 return TRUE;
351 }
352
353 METHOD(kernel_ipsec_t, destroy, void,
354 private_tkm_kernel_ipsec_t *this)
355 {
356 DESTROY_IF(this->rng);
357 free(this);
358 }
359
360 /*
361 * Described in header.
362 */
363 tkm_kernel_ipsec_t *tkm_kernel_ipsec_create()
364 {
365 private_tkm_kernel_ipsec_t *this;
366
367 INIT(this,
368 .public = {
369 .interface = {
370 .get_spi = _get_spi,
371 .get_cpi = _get_cpi,
372 .add_sa = _add_sa,
373 .update_sa = _update_sa,
374 .query_sa = _query_sa,
375 .del_sa = _del_sa,
376 .flush_sas = _flush_sas,
377 .add_policy = _add_policy,
378 .query_policy = _query_policy,
379 .del_policy = _del_policy,
380 .flush_policies = _flush_policies,
381 .bypass_socket = _bypass_socket,
382 .enable_udp_decap = _enable_udp_decap,
383 .destroy = _destroy,
384 },
385 },
386 );
387
388 return &this->public;
389 }