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