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