Use SAD to manage TKM ESA context information
[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_types.h"
27 #include "tkm_keymat.h"
28 #include "tkm_kernel_sad.h"
29 #include "tkm_kernel_ipsec.h"
30
31 typedef struct private_tkm_kernel_ipsec_t private_tkm_kernel_ipsec_t;
32
33 /**
34 * Private variables and functions of TKM kernel ipsec instance.
35 */
36 struct private_tkm_kernel_ipsec_t {
37
38 /**
39 * Public tkm_kernel_ipsec interface.
40 */
41 tkm_kernel_ipsec_t public;
42
43 /**
44 * RNG used for SPI generation.
45 */
46 rng_t *rng;
47
48 /**
49 * Local CHILD SA SPI.
50 */
51 uint32_t esp_spi_loc;
52
53 /**
54 * CHILD/ESP SA database.
55 */
56 tkm_kernel_sad_t *sad;
57
58 };
59
60 METHOD(kernel_ipsec_t, get_spi, status_t,
61 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
62 u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
63 {
64 DBG1(DBG_KNL, "getting SPI for reqid {%u}", reqid);
65 const bool result = this->rng->get_bytes(this->rng, sizeof(u_int32_t),
66 (u_int8_t *)spi);
67 return result ? SUCCESS : FAILED;
68 }
69
70 METHOD(kernel_ipsec_t, get_cpi, status_t,
71 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
72 u_int32_t reqid, u_int16_t *cpi)
73 {
74 return NOT_SUPPORTED;
75 }
76
77 METHOD(kernel_ipsec_t, add_sa, status_t,
78 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
79 u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
80 u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
81 u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
82 u_int16_t cpi, bool encap, bool esn, bool inbound,
83 traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
84 {
85 if (inbound && this->esp_spi_loc == 0)
86 {
87 DBG1(DBG_KNL, "store local child SA SPI for installation", ntohl(spi));
88 this->esp_spi_loc = spi;
89 return SUCCESS;
90 }
91 const esa_info_t esa = *(esa_info_t *)(enc_key.ptr);
92 const esa_id_type esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA);
93 DBG1(DBG_KNL, "adding child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, esp_spi_rem:"
94 " %x)", esa_id, esa.isa_id, ntohl(this->esp_spi_loc), ntohl(spi));
95 if (!this->sad->insert(this->sad, esa_id, src, dst, spi, protocol))
96 {
97 DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id);
98 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
99 return FAILED;
100 }
101 if (ike_esa_create_first(esa_id, esa.isa_id, 1, 1, ntohl(this->esp_spi_loc),
102 ntohl(spi)) != TKM_OK)
103 {
104 DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id);
105 this->sad->remove(this->sad, esa_id);
106 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
107 return FAILED;
108 }
109 this->esp_spi_loc = 0;
110 return SUCCESS;
111 }
112
113 METHOD(kernel_ipsec_t, query_sa, status_t,
114 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
115 u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes,
116 u_int64_t *packets)
117 {
118 return NOT_SUPPORTED;
119 }
120
121 METHOD(kernel_ipsec_t, del_sa, status_t,
122 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
123 u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark)
124 {
125 const esa_id_type esa_id = this->sad->get_esa_id(this->sad, src, dst, spi,
126 protocol);
127 if (esa_id)
128 {
129 DBG1(DBG_KNL, "deleting child SA (esa: %llu, spi: %x)", esa_id,
130 ntohl(spi));
131 if (ike_esa_reset(esa_id) != TKM_OK)
132 {
133 DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id);
134 return FAILED;
135 }
136 this->sad->remove(this->sad, esa_id);
137 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
138 }
139 return SUCCESS;
140 }
141
142 METHOD(kernel_ipsec_t, update_sa, status_t,
143 private_tkm_kernel_ipsec_t *this, u_int32_t spi, u_int8_t protocol,
144 u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
145 bool old_encap, bool new_encap, mark_t mark)
146 {
147 return NOT_SUPPORTED;
148 }
149
150 METHOD(kernel_ipsec_t, flush_sas, status_t,
151 private_tkm_kernel_ipsec_t *this)
152 {
153 DBG1(DBG_KNL, "flushing child SA entries");
154 return SUCCESS;
155 }
156
157 METHOD(kernel_ipsec_t, add_policy, status_t,
158 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
159 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
160 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
161 mark_t mark, policy_priority_t priority)
162 {
163 return SUCCESS;
164 }
165
166 METHOD(kernel_ipsec_t, query_policy, status_t,
167 private_tkm_kernel_ipsec_t *this, traffic_selector_t *src_ts,
168 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
169 u_int32_t *use_time)
170 {
171 return NOT_SUPPORTED;
172 }
173
174 METHOD(kernel_ipsec_t, del_policy, status_t,
175 private_tkm_kernel_ipsec_t *this, traffic_selector_t *src_ts,
176 traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
177 mark_t mark, policy_priority_t prio)
178 {
179 return SUCCESS;
180 }
181
182 METHOD(kernel_ipsec_t, flush_policies, status_t,
183 private_tkm_kernel_ipsec_t *this)
184 {
185 return SUCCESS;
186 }
187
188
189 METHOD(kernel_ipsec_t, bypass_socket, bool,
190 private_tkm_kernel_ipsec_t *this, int fd, int family)
191 {
192 struct xfrm_userpolicy_info policy;
193 u_int sol, ipsec_policy;
194
195 switch (family)
196 {
197 case AF_INET:
198 sol = SOL_IP;
199 ipsec_policy = IP_XFRM_POLICY;
200 break;
201 case AF_INET6:
202 sol = SOL_IPV6;
203 ipsec_policy = IPV6_XFRM_POLICY;
204 break;
205 default:
206 return FALSE;
207 }
208
209 memset(&policy, 0, sizeof(policy));
210 policy.action = XFRM_POLICY_ALLOW;
211 policy.sel.family = family;
212
213 policy.dir = XFRM_POLICY_OUT;
214 if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
215 {
216 DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
217 strerror(errno));
218 return FALSE;
219 }
220 policy.dir = XFRM_POLICY_IN;
221 if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
222 {
223 DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
224 strerror(errno));
225 return FALSE;
226 }
227 return TRUE;
228 }
229
230 METHOD(kernel_ipsec_t, enable_udp_decap, bool,
231 private_tkm_kernel_ipsec_t *this, int fd, int family, u_int16_t port)
232 {
233 int type = UDP_ENCAP_ESPINUDP;
234
235 if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
236 {
237 DBG1(DBG_KNL, "unable to set UDP_ENCAP: %s", strerror(errno));
238 return FALSE;
239 }
240 return TRUE;
241 }
242
243 METHOD(kernel_ipsec_t, destroy, void,
244 private_tkm_kernel_ipsec_t *this)
245 {
246 DESTROY_IF(this->rng);
247 DESTROY_IF(this->sad);
248 free(this);
249 }
250
251 /*
252 * Described in header.
253 */
254 tkm_kernel_ipsec_t *tkm_kernel_ipsec_create()
255 {
256 private_tkm_kernel_ipsec_t *this;
257
258 INIT(this,
259 .public = {
260 .interface = {
261 .get_spi = _get_spi,
262 .get_cpi = _get_cpi,
263 .add_sa = _add_sa,
264 .update_sa = _update_sa,
265 .query_sa = _query_sa,
266 .del_sa = _del_sa,
267 .flush_sas = _flush_sas,
268 .add_policy = _add_policy,
269 .query_policy = _query_policy,
270 .del_policy = _del_policy,
271 .flush_policies = _flush_policies,
272 .bypass_socket = _bypass_socket,
273 .enable_udp_decap = _enable_udp_decap,
274 .destroy = _destroy,
275 },
276 },
277 .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
278 .esp_spi_loc = 0,
279 .sad = tkm_kernel_sad_create(),
280 );
281
282 if (!this->rng)
283 {
284 DBG1(DBG_KNL, "unable to create RNG");
285 destroy(this);
286 return NULL;
287 }
288 if (!this->sad)
289 {
290 DBG1(DBG_KNL, "unable to create SAD");
291 destroy(this);
292 return NULL;
293 }
294
295 return &this->public;
296 }