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