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