]>
Commit | Line | Data |
---|---|---|
1adaa02b | 1 | /* |
6d86d0f5 | 2 | * Copyright (C) 2008-2017 Tobias Brunner |
c6362858 | 3 | * Copyright (C) 2008 Andreas Steffen |
89da06ac | 4 | * HSR Hochschule fuer Technik Rapperswil |
1adaa02b TB |
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. | |
1adaa02b | 15 | */ |
6afa7761 FK |
16 | /* |
17 | * Copyright (C) 2014 Nanoteq Pty Ltd | |
18 | * | |
19 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
20 | * of this software and associated documentation files (the "Software"), to deal | |
21 | * in the Software without restriction, including without limitation the rights | |
22 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
23 | * copies of the Software, and to permit persons to whom the Software is | |
24 | * furnished to do so, subject to the following conditions: | |
25 | * | |
26 | * The above copyright notice and this permission notice shall be included in | |
27 | * all copies or substantial portions of the Software. | |
28 | * | |
29 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
30 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
31 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
32 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
33 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
34 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
35 | * THE SOFTWARE. | |
36 | */ | |
1adaa02b | 37 | |
403ad5dd | 38 | #include <stdint.h> |
1adaa02b TB |
39 | #include <sys/types.h> |
40 | #include <sys/socket.h> | |
d24a74c5 | 41 | |
79ff6141 TB |
42 | #ifdef __FreeBSD__ |
43 | #include <limits.h> /* for LONG_MAX */ | |
44 | #endif | |
45 | ||
d24a74c5 TB |
46 | #ifdef HAVE_NET_PFKEYV2_H |
47 | #include <net/pfkeyv2.h> | |
48 | #else | |
1adaa02b | 49 | #include <linux/pfkeyv2.h> |
d24a74c5 TB |
50 | #endif |
51 | ||
52 | #ifdef SADB_X_EXT_NAT_T_TYPE | |
53 | #define HAVE_NATT | |
54 | #endif | |
55 | ||
56 | #ifdef HAVE_NETIPSEC_IPSEC_H | |
57 | #include <netipsec/ipsec.h> | |
9f090745 TB |
58 | #elif defined(HAVE_NETINET6_IPSEC_H) |
59 | #include <netinet6/ipsec.h> | |
d24a74c5 TB |
60 | #else |
61 | #include <linux/ipsec.h> | |
62 | #endif | |
63 | ||
64 | #ifdef HAVE_NATT | |
1e7b4b00 | 65 | #ifdef HAVE_LINUX_UDP_H |
1adaa02b | 66 | #include <linux/udp.h> |
1e7b4b00 TB |
67 | #else |
68 | #include <netinet/udp.h> | |
69 | #endif /*HAVE_LINUX_UDP_H*/ | |
d24a74c5 TB |
70 | #endif /*HAVE_NATT*/ |
71 | ||
1adaa02b | 72 | #include <unistd.h> |
4a5a5dd2 | 73 | #include <time.h> |
1adaa02b | 74 | #include <errno.h> |
e49abced TB |
75 | #ifdef __APPLE__ |
76 | #include <sys/sysctl.h> | |
77 | #endif | |
1adaa02b TB |
78 | |
79 | #include "kernel_pfkey_ipsec.h" | |
80 | ||
8394ea2a | 81 | #include <daemon.h> |
f05b4272 | 82 | #include <utils/debug.h> |
2e7cc07e | 83 | #include <networking/host.h> |
12642a68 TB |
84 | #include <collections/linked_list.h> |
85 | #include <collections/hashtable.h> | |
eba64cef | 86 | #include <threading/mutex.h> |
1adaa02b | 87 | |
d24a74c5 TB |
88 | /** non linux specific */ |
89 | #ifndef IPPROTO_COMP | |
b7900d32 | 90 | #ifdef IPPROTO_IPCOMP |
d24a74c5 TB |
91 | #define IPPROTO_COMP IPPROTO_IPCOMP |
92 | #endif | |
b7900d32 | 93 | #endif |
d24a74c5 TB |
94 | |
95 | #ifndef SADB_X_AALG_SHA2_256HMAC | |
96 | #define SADB_X_AALG_SHA2_256HMAC SADB_X_AALG_SHA2_256 | |
97 | #define SADB_X_AALG_SHA2_384HMAC SADB_X_AALG_SHA2_384 | |
98 | #define SADB_X_AALG_SHA2_512HMAC SADB_X_AALG_SHA2_512 | |
99 | #endif | |
100 | ||
101 | #ifndef SADB_X_EALG_AESCBC | |
102 | #define SADB_X_EALG_AESCBC SADB_X_EALG_AES | |
103 | #endif | |
104 | ||
105 | #ifndef SADB_X_EALG_CASTCBC | |
106 | #define SADB_X_EALG_CASTCBC SADB_X_EALG_CAST128CBC | |
107 | #endif | |
108 | ||
e2a252a8 TB |
109 | #if !defined(SADB_X_EALG_AES_GCM_ICV8) && defined(SADB_X_EALG_AESGCM8) |
110 | #define SADB_X_EALG_AES_GCM_ICV8 SADB_X_EALG_AESGCM8 | |
111 | #define SADB_X_EALG_AES_GCM_ICV12 SADB_X_EALG_AESGCM12 | |
112 | #define SADB_X_EALG_AES_GCM_ICV16 SADB_X_EALG_AESGCM16 | |
113 | #endif | |
114 | ||
d24a74c5 TB |
115 | #ifndef SOL_IP |
116 | #define SOL_IP IPPROTO_IP | |
117 | #define SOL_IPV6 IPPROTO_IPV6 | |
118 | #endif | |
119 | ||
ea625fab TB |
120 | /** from linux/in.h */ |
121 | #ifndef IP_IPSEC_POLICY | |
122 | #define IP_IPSEC_POLICY 16 | |
123 | #endif | |
124 | ||
e20bd8b6 | 125 | /** missing on uclibc */ |
addfea95 MW |
126 | #ifndef IPV6_IPSEC_POLICY |
127 | #define IPV6_IPSEC_POLICY 34 | |
d24a74c5 | 128 | #endif |
addfea95 | 129 | |
e49abced TB |
130 | /* from linux/udp.h */ |
131 | #ifndef UDP_ENCAP | |
132 | #define UDP_ENCAP 100 | |
133 | #endif | |
134 | ||
135 | #ifndef UDP_ENCAP_ESPINUDP | |
136 | #define UDP_ENCAP_ESPINUDP 2 | |
137 | #endif | |
138 | ||
139 | /* this is not defined on some platforms */ | |
140 | #ifndef SOL_UDP | |
141 | #define SOL_UDP IPPROTO_UDP | |
142 | #endif | |
143 | ||
4e596183 | 144 | /** Base priority for installed policies */ |
3c46ce28 | 145 | #define PRIO_BASE 200000 |
1adaa02b | 146 | |
e20bd8b6 TB |
147 | #ifdef __APPLE__ |
148 | /** from xnu/bsd/net/pfkeyv2.h */ | |
149 | #define SADB_X_EXT_NATT 0x002 | |
150 | struct sadb_sa_2 { | |
151 | struct sadb_sa sa; | |
b12c53ce AS |
152 | uint16_t sadb_sa_natt_port; |
153 | uint16_t sadb_reserved0; | |
154 | uint32_t sadb_reserved1; | |
e20bd8b6 TB |
155 | }; |
156 | #endif | |
157 | ||
1adaa02b | 158 | /** buffer size for PF_KEY messages */ |
e526d228 | 159 | #define PFKEY_BUFFER_SIZE 4096 |
1adaa02b TB |
160 | |
161 | /** PF_KEY messages are 64 bit aligned */ | |
162 | #define PFKEY_ALIGNMENT 8 | |
163 | /** aligns len to 64 bits */ | |
164 | #define PFKEY_ALIGN(len) (((len) + PFKEY_ALIGNMENT - 1) & ~(PFKEY_ALIGNMENT - 1)) | |
165 | /** calculates the properly padded length in 64 bit chunks */ | |
166 | #define PFKEY_LEN(len) ((PFKEY_ALIGN(len) / PFKEY_ALIGNMENT)) | |
167 | /** calculates user mode length i.e. in bytes */ | |
168 | #define PFKEY_USER_LEN(len) ((len) * PFKEY_ALIGNMENT) | |
169 | ||
170 | /** given a PF_KEY message header and an extension this updates the length in the header */ | |
171 | #define PFKEY_EXT_ADD(msg, ext) ((msg)->sadb_msg_len += ((struct sadb_ext*)ext)->sadb_ext_len) | |
172 | /** given a PF_KEY message header this returns a pointer to the next extension */ | |
173 | #define PFKEY_EXT_ADD_NEXT(msg) ((struct sadb_ext*)(((char*)(msg)) + PFKEY_USER_LEN((msg)->sadb_msg_len))) | |
174 | /** copy an extension and append it to a PF_KEY message */ | |
175 | #define PFKEY_EXT_COPY(msg, ext) (PFKEY_EXT_ADD(msg, memcpy(PFKEY_EXT_ADD_NEXT(msg), ext, PFKEY_USER_LEN(((struct sadb_ext*)ext)->sadb_ext_len)))) | |
176 | /** given a PF_KEY extension this returns a pointer to the next extension */ | |
177 | #define PFKEY_EXT_NEXT(ext) ((struct sadb_ext*)(((char*)(ext)) + PFKEY_USER_LEN(((struct sadb_ext*)ext)->sadb_ext_len))) | |
178 | /** given a PF_KEY extension this returns a pointer to the next extension also updates len (len in 64 bit words) */ | |
179 | #define PFKEY_EXT_NEXT_LEN(ext,len) ((len) -= (ext)->sadb_ext_len, PFKEY_EXT_NEXT(ext)) | |
180 | /** true if ext has a valid length and len is large enough to contain ext (assuming len in 64 bit words) */ | |
181 | #define PFKEY_EXT_OK(ext,len) ((len) >= PFKEY_LEN(sizeof(struct sadb_ext)) && \ | |
182 | (ext)->sadb_ext_len >= PFKEY_LEN(sizeof(struct sadb_ext)) && \ | |
183 | (ext)->sadb_ext_len <= (len)) | |
184 | ||
185 | typedef struct private_kernel_pfkey_ipsec_t private_kernel_pfkey_ipsec_t; | |
186 | ||
187 | /** | |
188 | * Private variables and functions of kernel_pfkey class. | |
189 | */ | |
190 | struct private_kernel_pfkey_ipsec_t | |
191 | { | |
192 | /** | |
193 | * Public part of the kernel_pfkey_t object. | |
194 | */ | |
195 | kernel_pfkey_ipsec_t public; | |
7daf5226 | 196 | |
1adaa02b TB |
197 | /** |
198 | * mutex to lock access to various lists | |
199 | */ | |
3ac5a0db | 200 | mutex_t *mutex; |
7daf5226 | 201 | |
1adaa02b TB |
202 | /** |
203 | * List of installed policies (policy_entry_t) | |
204 | */ | |
205 | linked_list_t *policies; | |
7daf5226 | 206 | |
df919d50 MW |
207 | /** |
208 | * List of exclude routes (exclude_route_t) | |
209 | */ | |
210 | linked_list_t *excludes; | |
211 | ||
17927ca6 TB |
212 | /** |
213 | * Hash table of IPsec SAs using policies (ipsec_sa_t) | |
214 | */ | |
215 | hashtable_t *sas; | |
216 | ||
1adaa02b TB |
217 | /** |
218 | * whether to install routes along policies | |
219 | */ | |
220 | bool install_routes; | |
7daf5226 | 221 | |
e8116593 TB |
222 | /** |
223 | * whether to install the route via internal interface | |
224 | */ | |
225 | bool route_via_internal; | |
226 | ||
1adaa02b TB |
227 | /** |
228 | * mutex to lock access to the PF_KEY socket | |
229 | */ | |
3ac5a0db | 230 | mutex_t *mutex_pfkey; |
7daf5226 | 231 | |
1adaa02b TB |
232 | /** |
233 | * PF_KEY socket to communicate with the kernel | |
234 | */ | |
235 | int socket; | |
7daf5226 | 236 | |
1adaa02b TB |
237 | /** |
238 | * PF_KEY socket to receive acquire and expire events | |
239 | */ | |
240 | int socket_events; | |
7daf5226 | 241 | |
1adaa02b TB |
242 | /** |
243 | * sequence number for messages sent to the kernel | |
244 | */ | |
245 | int seq; | |
246 | }; | |
247 | ||
df919d50 MW |
248 | typedef struct exclude_route_t exclude_route_t; |
249 | ||
250 | /** | |
251 | * Exclude route definition | |
252 | */ | |
253 | struct exclude_route_t { | |
254 | /** destination address of exclude */ | |
255 | host_t *dst; | |
256 | /** source address for route */ | |
257 | host_t *src; | |
258 | /** nexthop exclude has been installed */ | |
259 | host_t *gtw; | |
260 | /** references to this route */ | |
261 | int refs; | |
262 | }; | |
263 | ||
264 | /** | |
265 | * clean up a route exclude entry | |
266 | */ | |
267 | static void exclude_route_destroy(exclude_route_t *this) | |
268 | { | |
269 | this->dst->destroy(this->dst); | |
270 | this->src->destroy(this->src); | |
271 | this->gtw->destroy(this->gtw); | |
272 | free(this); | |
273 | } | |
274 | ||
1adaa02b TB |
275 | typedef struct route_entry_t route_entry_t; |
276 | ||
277 | /** | |
278 | * installed routing entry | |
279 | */ | |
280 | struct route_entry_t { | |
108357b1 | 281 | /** name of the interface the route is bound to */ |
1adaa02b | 282 | char *if_name; |
7daf5226 | 283 | |
108357b1 | 284 | /** source ip of the route */ |
1adaa02b | 285 | host_t *src_ip; |
7daf5226 | 286 | |
1adaa02b TB |
287 | /** gateway for this route */ |
288 | host_t *gateway; | |
289 | ||
108357b1 | 290 | /** destination net */ |
1adaa02b TB |
291 | chunk_t dst_net; |
292 | ||
108357b1 | 293 | /** destination net prefixlen */ |
b12c53ce | 294 | uint8_t prefixlen; |
df919d50 MW |
295 | |
296 | /** reference to exclude route, if any */ | |
297 | exclude_route_t *exclude; | |
1adaa02b TB |
298 | }; |
299 | ||
300 | /** | |
301 | * destroy an route_entry_t object | |
302 | */ | |
303 | static void route_entry_destroy(route_entry_t *this) | |
304 | { | |
305 | free(this->if_name); | |
d24a74c5 TB |
306 | DESTROY_IF(this->src_ip); |
307 | DESTROY_IF(this->gateway); | |
1adaa02b TB |
308 | chunk_free(&this->dst_net); |
309 | free(this); | |
310 | } | |
311 | ||
17927ca6 TB |
312 | /** |
313 | * compare two route_entry_t objects | |
314 | */ | |
315 | static bool route_entry_equals(route_entry_t *a, route_entry_t *b) | |
316 | { | |
317 | return a->if_name && b->if_name && streq(a->if_name, b->if_name) && | |
9896b6bd | 318 | a->src_ip->ip_equals(a->src_ip, b->src_ip) && |
f8646dd6 | 319 | a->gateway && b->gateway && |
9896b6bd | 320 | a->gateway->ip_equals(a->gateway, b->gateway) && |
17927ca6 TB |
321 | chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen; |
322 | } | |
323 | ||
324 | typedef struct ipsec_sa_t ipsec_sa_t; | |
325 | ||
326 | /** | |
327 | * IPsec SA assigned to a policy. | |
328 | */ | |
329 | struct ipsec_sa_t { | |
330 | /** Source address of this SA */ | |
331 | host_t *src; | |
332 | ||
333 | /** Destination address of this SA */ | |
334 | host_t *dst; | |
335 | ||
336 | /** Description of this SA */ | |
337 | ipsec_sa_cfg_t cfg; | |
338 | ||
339 | /** Reference count for this SA */ | |
340 | refcount_t refcount; | |
341 | }; | |
342 | ||
343 | /** | |
344 | * Hash function for ipsec_sa_t objects | |
345 | */ | |
346 | static u_int ipsec_sa_hash(ipsec_sa_t *sa) | |
347 | { | |
348 | return chunk_hash_inc(sa->src->get_address(sa->src), | |
349 | chunk_hash_inc(sa->dst->get_address(sa->dst), | |
350 | chunk_hash(chunk_from_thing(sa->cfg)))); | |
351 | } | |
352 | ||
353 | /** | |
354 | * Equality function for ipsec_sa_t objects | |
355 | */ | |
356 | static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa) | |
357 | { | |
358 | return sa->src->ip_equals(sa->src, other_sa->src) && | |
359 | sa->dst->ip_equals(sa->dst, other_sa->dst) && | |
1ba2b015 | 360 | ipsec_sa_cfg_equals(&sa->cfg, &other_sa->cfg); |
17927ca6 TB |
361 | } |
362 | ||
363 | /** | |
364 | * Allocate or reference an IPsec SA object | |
365 | */ | |
366 | static ipsec_sa_t *ipsec_sa_create(private_kernel_pfkey_ipsec_t *this, | |
367 | host_t *src, host_t *dst, | |
368 | ipsec_sa_cfg_t *cfg) | |
369 | { | |
370 | ipsec_sa_t *sa, *found; | |
371 | INIT(sa, | |
372 | .src = src, | |
373 | .dst = dst, | |
374 | .cfg = *cfg, | |
375 | ); | |
376 | found = this->sas->get(this->sas, sa); | |
377 | if (!found) | |
378 | { | |
379 | sa->src = src->clone(src); | |
380 | sa->dst = dst->clone(dst); | |
381 | this->sas->put(this->sas, sa, sa); | |
382 | } | |
383 | else | |
384 | { | |
385 | free(sa); | |
386 | sa = found; | |
387 | } | |
388 | ref_get(&sa->refcount); | |
389 | return sa; | |
390 | } | |
391 | ||
392 | /** | |
393 | * Release and destroy an IPsec SA object | |
394 | */ | |
395 | static void ipsec_sa_destroy(private_kernel_pfkey_ipsec_t *this, | |
396 | ipsec_sa_t *sa) | |
397 | { | |
398 | if (ref_put(&sa->refcount)) | |
399 | { | |
400 | this->sas->remove(this->sas, sa); | |
401 | DESTROY_IF(sa->src); | |
402 | DESTROY_IF(sa->dst); | |
403 | free(sa); | |
404 | } | |
405 | } | |
406 | ||
407 | typedef struct policy_sa_t policy_sa_t; | |
b98afc0a | 408 | typedef struct policy_sa_out_t policy_sa_out_t; |
17927ca6 TB |
409 | |
410 | /** | |
411 | * Mapping between a policy and an IPsec SA. | |
412 | */ | |
413 | struct policy_sa_t { | |
414 | /** Priority assigned to the policy when installed with this SA */ | |
b12c53ce | 415 | uint32_t priority; |
17927ca6 | 416 | |
254726b5 TB |
417 | /** Base priority assigned to the policy when installed with this SA */ |
418 | uint32_t auto_priority; | |
419 | ||
17927ca6 TB |
420 | /** Type of the policy */ |
421 | policy_type_t type; | |
422 | ||
423 | /** Assigned SA */ | |
424 | ipsec_sa_t *sa; | |
425 | }; | |
426 | ||
427 | /** | |
b98afc0a | 428 | * For outbound policies we also cache the traffic selectors in order to install |
17927ca6 TB |
429 | * the route. |
430 | */ | |
b98afc0a | 431 | struct policy_sa_out_t { |
17927ca6 TB |
432 | /** Generic interface */ |
433 | policy_sa_t generic; | |
434 | ||
435 | /** Source traffic selector of this policy */ | |
436 | traffic_selector_t *src_ts; | |
437 | ||
438 | /** Destination traffic selector of this policy */ | |
439 | traffic_selector_t *dst_ts; | |
440 | }; | |
441 | ||
442 | /** | |
d4260c5f | 443 | * Create a policy_sa(_in)_t object |
17927ca6 TB |
444 | */ |
445 | static policy_sa_t *policy_sa_create(private_kernel_pfkey_ipsec_t *this, | |
446 | policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst, | |
447 | traffic_selector_t *src_ts, traffic_selector_t *dst_ts, ipsec_sa_cfg_t *cfg) | |
448 | { | |
449 | policy_sa_t *policy; | |
450 | ||
b98afc0a | 451 | if (dir == POLICY_OUT) |
17927ca6 | 452 | { |
b98afc0a TB |
453 | policy_sa_out_t *out; |
454 | INIT(out, | |
17927ca6 TB |
455 | .src_ts = src_ts->clone(src_ts), |
456 | .dst_ts = dst_ts->clone(dst_ts), | |
457 | ); | |
b98afc0a | 458 | policy = &out->generic; |
17927ca6 TB |
459 | } |
460 | else | |
461 | { | |
25d59e9e | 462 | INIT(policy, .priority = 0); |
17927ca6 TB |
463 | } |
464 | policy->type = type; | |
465 | policy->sa = ipsec_sa_create(this, src, dst, cfg); | |
466 | return policy; | |
467 | } | |
468 | ||
469 | /** | |
d4260c5f | 470 | * Destroy a policy_sa(_in)_t object |
17927ca6 | 471 | */ |
8a2e4d4a | 472 | static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t dir, |
17927ca6 TB |
473 | private_kernel_pfkey_ipsec_t *this) |
474 | { | |
8a2e4d4a | 475 | if (dir == POLICY_OUT) |
17927ca6 | 476 | { |
b98afc0a TB |
477 | policy_sa_out_t *out = (policy_sa_out_t*)policy; |
478 | out->src_ts->destroy(out->src_ts); | |
479 | out->dst_ts->destroy(out->dst_ts); | |
17927ca6 TB |
480 | } |
481 | ipsec_sa_destroy(this, policy->sa); | |
482 | free(policy); | |
483 | } | |
484 | ||
8a2e4d4a TB |
485 | CALLBACK(policy_sa_destroy_cb, void, |
486 | policy_sa_t *policy, va_list args) | |
487 | { | |
488 | private_kernel_pfkey_ipsec_t *this; | |
489 | policy_dir_t dir; | |
490 | ||
491 | VA_ARGS_VGET(args, dir, this); | |
492 | policy_sa_destroy(policy, dir, this); | |
493 | } | |
494 | ||
1adaa02b TB |
495 | typedef struct policy_entry_t policy_entry_t; |
496 | ||
497 | /** | |
498 | * installed kernel policy. | |
499 | */ | |
500 | struct policy_entry_t { | |
17927ca6 | 501 | /** Index assigned by the kernel */ |
b12c53ce | 502 | uint32_t index; |
7daf5226 | 503 | |
17927ca6 | 504 | /** Direction of this policy: in, out, forward */ |
b12c53ce | 505 | uint8_t direction; |
7daf5226 | 506 | |
17927ca6 | 507 | /** Parameters of installed policy */ |
1adaa02b | 508 | struct { |
17927ca6 | 509 | /** Subnet and port */ |
1adaa02b | 510 | host_t *net; |
17927ca6 | 511 | /** Subnet mask */ |
b12c53ce | 512 | uint8_t mask; |
17927ca6 | 513 | /** Protocol */ |
b12c53ce | 514 | uint8_t proto; |
1adaa02b | 515 | } src, dst; |
7daf5226 | 516 | |
17927ca6 | 517 | /** Associated route installed for this policy */ |
1adaa02b | 518 | route_entry_t *route; |
7daf5226 | 519 | |
17927ca6 TB |
520 | /** List of SAs this policy is used by, ordered by priority */ |
521 | linked_list_t *used_by; | |
1adaa02b TB |
522 | }; |
523 | ||
524 | /** | |
17927ca6 | 525 | * Create a policy_entry_t object |
1adaa02b TB |
526 | */ |
527 | static policy_entry_t *create_policy_entry(traffic_selector_t *src_ts, | |
17927ca6 TB |
528 | traffic_selector_t *dst_ts, |
529 | policy_dir_t dir) | |
1adaa02b | 530 | { |
108357b1 TB |
531 | policy_entry_t *policy; |
532 | INIT(policy, | |
108357b1 TB |
533 | .direction = dir, |
534 | ); | |
b12c53ce AS |
535 | uint16_t port; |
536 | uint8_t proto; | |
7daf5226 | 537 | |
1adaa02b TB |
538 | src_ts->to_subnet(src_ts, &policy->src.net, &policy->src.mask); |
539 | dst_ts->to_subnet(dst_ts, &policy->dst.net, &policy->dst.mask); | |
7daf5226 | 540 | |
1adaa02b | 541 | /* src or dest proto may be "any" (0), use more restrictive one */ |
d34a82dd TB |
542 | proto = max(src_ts->get_protocol(src_ts), dst_ts->get_protocol(dst_ts)); |
543 | /* map the ports to ICMP type/code how the Linux kernel expects them, that | |
544 | * is, type in src, code in dst */ | |
545 | if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) | |
546 | { | |
547 | port = max(policy->src.net->get_port(policy->src.net), | |
548 | policy->dst.net->get_port(policy->dst.net)); | |
549 | policy->src.net->set_port(policy->src.net, | |
550 | traffic_selector_icmp_type(port)); | |
551 | policy->dst.net->set_port(policy->dst.net, | |
552 | traffic_selector_icmp_code(port)); | |
553 | } | |
554 | else if (!proto) | |
555 | { | |
556 | proto = IPSEC_PROTO_ANY; | |
557 | } | |
558 | policy->src.proto = policy->dst.proto = proto; | |
7daf5226 | 559 | |
1adaa02b TB |
560 | return policy; |
561 | } | |
562 | ||
563 | /** | |
17927ca6 | 564 | * Destroy a policy_entry_t object |
1adaa02b | 565 | */ |
17927ca6 TB |
566 | static void policy_entry_destroy(policy_entry_t *policy, |
567 | private_kernel_pfkey_ipsec_t *this) | |
1adaa02b | 568 | { |
17927ca6 | 569 | if (policy->route) |
1adaa02b | 570 | { |
17927ca6 | 571 | route_entry_destroy(policy->route); |
1adaa02b | 572 | } |
17927ca6 TB |
573 | if (policy->used_by) |
574 | { | |
8a2e4d4a TB |
575 | policy->used_by->invoke_function(policy->used_by, policy_sa_destroy_cb, |
576 | policy->direction, this); | |
17927ca6 TB |
577 | policy->used_by->destroy(policy->used_by); |
578 | } | |
579 | DESTROY_IF(policy->src.net); | |
580 | DESTROY_IF(policy->dst.net); | |
581 | free(policy); | |
1adaa02b TB |
582 | } |
583 | ||
8a2e4d4a TB |
584 | CALLBACK(policy_entry_destroy_cb, void, |
585 | policy_entry_t *policy, va_list args) | |
586 | { | |
587 | private_kernel_pfkey_ipsec_t *this; | |
588 | ||
589 | VA_ARGS_VGET(args, this); | |
590 | policy_entry_destroy(policy, this); | |
591 | } | |
592 | ||
2e4d110d TB |
593 | CALLBACK(policy_entry_equals, bool, |
594 | policy_entry_t *current, va_list args) | |
1adaa02b | 595 | { |
2e4d110d TB |
596 | policy_entry_t *policy; |
597 | ||
598 | VA_ARGS_VGET(args, policy); | |
1adaa02b TB |
599 | return current->direction == policy->direction && |
600 | current->src.proto == policy->src.proto && | |
601 | current->dst.proto == policy->dst.proto && | |
602 | current->src.mask == policy->src.mask && | |
603 | current->dst.mask == policy->dst.mask && | |
604 | current->src.net->equals(current->src.net, policy->src.net) && | |
605 | current->dst.net->equals(current->dst.net, policy->dst.net); | |
606 | } | |
607 | ||
2e4d110d TB |
608 | CALLBACK(policy_entry_match_byindex, bool, |
609 | policy_entry_t *current, va_list args) | |
1adaa02b | 610 | { |
2e4d110d TB |
611 | uint32_t index; |
612 | ||
613 | VA_ARGS_VGET(args, index); | |
614 | return current->index == index; | |
1adaa02b TB |
615 | } |
616 | ||
fbedc6a4 TB |
617 | /** |
618 | * Calculate the priority of a policy | |
4e596183 TB |
619 | * |
620 | * This is the same formula we use in the kernel-netlink interface, but some | |
621 | * features are currently not or only partially supported by PF_KEY. | |
622 | * | |
3c46ce28 TB |
623 | * bits 0-0: separate trap and regular policies (0..1) 1 bit |
624 | * bits 1-1: reserved for interface restriction (0..1) 1 bit | |
625 | * bits 2-7: src + dst port mask bits (2 * 0..16) 6 bits | |
626 | * bits 8-8: restriction to protocol (0..1) 1 bit | |
627 | * bits 9-17: src + dst network mask bits (2 * 0..128) 9 bits | |
628 | * 18 bits | |
4e596183 | 629 | * |
3c46ce28 TB |
630 | * smallest value: 000000000 0 000000 0 0: 0, lowest priority = 100'000 |
631 | * largest value : 100000000 1 100000 0 1: 131'457, highst priority = 68'543 | |
fbedc6a4 | 632 | */ |
b12c53ce | 633 | static inline uint32_t get_priority(policy_entry_t *policy, |
3c46ce28 | 634 | policy_priority_t prio) |
fbedc6a4 | 635 | { |
b12c53ce | 636 | uint32_t priority = PRIO_BASE; |
4e596183 | 637 | |
fbedc6a4 TB |
638 | switch (prio) |
639 | { | |
d7a59f19 | 640 | case POLICY_PRIORITY_FALLBACK: |
4e596183 | 641 | priority += PRIO_BASE; |
d7a59f19 | 642 | /* fall-through */ |
fbedc6a4 | 643 | case POLICY_PRIORITY_ROUTED: |
fbedc6a4 | 644 | case POLICY_PRIORITY_DEFAULT: |
4e596183 TB |
645 | priority += PRIO_BASE; |
646 | /* fall-through */ | |
77b6a145 | 647 | case POLICY_PRIORITY_PASS: |
fbedc6a4 TB |
648 | break; |
649 | } | |
4e596183 TB |
650 | |
651 | /* calculate priority */ | |
3c46ce28 TB |
652 | priority -= (policy->src.mask + policy->dst.mask) * 512; |
653 | priority -= policy->src.proto != IPSEC_PROTO_ANY ? 256 : 0; | |
654 | priority -= policy->src.net->get_port(policy->src.net) ? 64 : 0; | |
655 | priority -= policy->dst.net->get_port(policy->dst.net) ? 64 : 0; | |
656 | priority -= (prio != POLICY_PRIORITY_ROUTED); | |
fbedc6a4 TB |
657 | return priority; |
658 | } | |
659 | ||
1adaa02b TB |
660 | typedef struct pfkey_msg_t pfkey_msg_t; |
661 | ||
662 | struct pfkey_msg_t | |
663 | { | |
664 | /** | |
665 | * PF_KEY message base | |
666 | */ | |
667 | struct sadb_msg *msg; | |
7daf5226 | 668 | |
1adaa02b TB |
669 | /** |
670 | * PF_KEY message extensions | |
671 | */ | |
672 | union { | |
673 | struct sadb_ext *ext[SADB_EXT_MAX + 1]; | |
674 | struct { | |
675 | struct sadb_ext *reserved; /* SADB_EXT_RESERVED */ | |
676 | struct sadb_sa *sa; /* SADB_EXT_SA */ | |
677 | struct sadb_lifetime *lft_current; /* SADB_EXT_LIFETIME_CURRENT */ | |
678 | struct sadb_lifetime *lft_hard; /* SADB_EXT_LIFETIME_HARD */ | |
679 | struct sadb_lifetime *lft_soft; /* SADB_EXT_LIFETIME_SOFT */ | |
680 | struct sadb_address *src; /* SADB_EXT_ADDRESS_SRC */ | |
681 | struct sadb_address *dst; /* SADB_EXT_ADDRESS_DST */ | |
682 | struct sadb_address *proxy; /* SADB_EXT_ADDRESS_PROXY */ | |
683 | struct sadb_key *key_auth; /* SADB_EXT_KEY_AUTH */ | |
684 | struct sadb_key *key_encr; /* SADB_EXT_KEY_ENCRYPT */ | |
685 | struct sadb_ident *id_src; /* SADB_EXT_IDENTITY_SRC */ | |
686 | struct sadb_ident *id_dst; /* SADB_EXT_IDENTITY_DST */ | |
687 | struct sadb_sens *sensitivity; /* SADB_EXT_SENSITIVITY */ | |
688 | struct sadb_prop *proposal; /* SADB_EXT_PROPOSAL */ | |
689 | struct sadb_supported *supported_auth; /* SADB_EXT_SUPPORTED_AUTH */ | |
690 | struct sadb_supported *supported_encr; /* SADB_EXT_SUPPORTED_ENCRYPT */ | |
691 | struct sadb_spirange *spirange; /* SADB_EXT_SPIRANGE */ | |
692 | struct sadb_x_kmprivate *x_kmprivate; /* SADB_X_EXT_KMPRIVATE */ | |
693 | struct sadb_x_policy *x_policy; /* SADB_X_EXT_POLICY */ | |
694 | struct sadb_x_sa2 *x_sa2; /* SADB_X_EXT_SA2 */ | |
695 | struct sadb_x_nat_t_type *x_natt_type; /* SADB_X_EXT_NAT_T_TYPE */ | |
696 | struct sadb_x_nat_t_port *x_natt_sport; /* SADB_X_EXT_NAT_T_SPORT */ | |
697 | struct sadb_x_nat_t_port *x_natt_dport; /* SADB_X_EXT_NAT_T_DPORT */ | |
698 | struct sadb_address *x_natt_oa; /* SADB_X_EXT_NAT_T_OA */ | |
699 | struct sadb_x_sec_ctx *x_sec_ctx; /* SADB_X_EXT_SEC_CTX */ | |
e526d228 | 700 | struct sadb_x_kmaddress *x_kmaddress; /* SADB_X_EXT_KMADDRESS */ |
1adaa02b TB |
701 | } __attribute__((__packed__)); |
702 | }; | |
703 | }; | |
704 | ||
d24a74c5 | 705 | ENUM(sadb_ext_type_names, SADB_EXT_RESERVED, SADB_EXT_MAX, |
e526d228 AS |
706 | "SADB_EXT_RESERVED", |
707 | "SADB_EXT_SA", | |
708 | "SADB_EXT_LIFETIME_CURRENT", | |
709 | "SADB_EXT_LIFETIME_HARD", | |
710 | "SADB_EXT_LIFETIME_SOFT", | |
711 | "SADB_EXT_ADDRESS_SRC", | |
712 | "SADB_EXT_ADDRESS_DST", | |
713 | "SADB_EXT_ADDRESS_PROXY", | |
714 | "SADB_EXT_KEY_AUTH", | |
715 | "SADB_EXT_KEY_ENCRYPT", | |
716 | "SADB_EXT_IDENTITY_SRC", | |
717 | "SADB_EXT_IDENTITY_DST", | |
718 | "SADB_EXT_SENSITIVITY", | |
719 | "SADB_EXT_PROPOSAL", | |
720 | "SADB_EXT_SUPPORTED_AUTH", | |
721 | "SADB_EXT_SUPPORTED_ENCRYPT", | |
722 | "SADB_EXT_SPIRANGE", | |
723 | "SADB_X_EXT_KMPRIVATE", | |
724 | "SADB_X_EXT_POLICY", | |
725 | "SADB_X_EXT_SA2", | |
726 | "SADB_X_EXT_NAT_T_TYPE", | |
727 | "SADB_X_EXT_NAT_T_SPORT", | |
728 | "SADB_X_EXT_NAT_T_DPORT", | |
729 | "SADB_X_EXT_NAT_T_OA", | |
730 | "SADB_X_EXT_SEC_CTX", | |
731 | "SADB_X_EXT_KMADDRESS" | |
732 | ); | |
d24a74c5 | 733 | |
1adaa02b | 734 | /** |
9f166d9a | 735 | * convert a protocol identifier to the PF_KEY sa type |
1adaa02b | 736 | */ |
b12c53ce | 737 | static uint8_t proto2satype(uint8_t proto) |
1adaa02b TB |
738 | { |
739 | switch (proto) | |
740 | { | |
9f166d9a | 741 | case IPPROTO_ESP: |
1adaa02b | 742 | return SADB_SATYPE_ESP; |
9f166d9a | 743 | case IPPROTO_AH: |
1adaa02b TB |
744 | return SADB_SATYPE_AH; |
745 | case IPPROTO_COMP: | |
746 | return SADB_X_SATYPE_IPCOMP; | |
747 | default: | |
748 | return proto; | |
749 | } | |
750 | } | |
751 | ||
752 | /** | |
9f166d9a | 753 | * convert a PF_KEY sa type to a protocol identifier |
1adaa02b | 754 | */ |
b12c53ce | 755 | static uint8_t satype2proto(uint8_t satype) |
1adaa02b | 756 | { |
9f166d9a | 757 | switch (satype) |
1adaa02b TB |
758 | { |
759 | case SADB_SATYPE_ESP: | |
9f166d9a | 760 | return IPPROTO_ESP; |
1adaa02b | 761 | case SADB_SATYPE_AH: |
9f166d9a | 762 | return IPPROTO_AH; |
1adaa02b TB |
763 | case SADB_X_SATYPE_IPCOMP: |
764 | return IPPROTO_COMP; | |
765 | default: | |
9f166d9a | 766 | return satype; |
1adaa02b TB |
767 | } |
768 | } | |
769 | ||
770 | /** | |
771 | * convert the general ipsec mode to the one defined in ipsec.h | |
772 | */ | |
b12c53ce | 773 | static uint8_t mode2kernel(ipsec_mode_t mode) |
1adaa02b TB |
774 | { |
775 | switch (mode) | |
776 | { | |
777 | case MODE_TRANSPORT: | |
778 | return IPSEC_MODE_TRANSPORT; | |
779 | case MODE_TUNNEL: | |
780 | return IPSEC_MODE_TUNNEL; | |
617e59b7 | 781 | #ifdef HAVE_IPSEC_MODE_BEET |
1adaa02b TB |
782 | case MODE_BEET: |
783 | return IPSEC_MODE_BEET; | |
d24a74c5 | 784 | #endif |
1adaa02b TB |
785 | default: |
786 | return mode; | |
787 | } | |
788 | } | |
789 | ||
790 | /** | |
791 | * convert the general policy direction to the one defined in ipsec.h | |
792 | */ | |
b12c53ce | 793 | static uint8_t dir2kernel(policy_dir_t dir) |
1adaa02b TB |
794 | { |
795 | switch (dir) | |
796 | { | |
797 | case POLICY_IN: | |
798 | return IPSEC_DIR_INBOUND; | |
799 | case POLICY_OUT: | |
800 | return IPSEC_DIR_OUTBOUND; | |
617e59b7 | 801 | #ifdef HAVE_IPSEC_DIR_FWD |
1adaa02b TB |
802 | case POLICY_FWD: |
803 | return IPSEC_DIR_FWD; | |
d24a74c5 | 804 | #endif |
1adaa02b | 805 | default: |
eab05274 | 806 | return IPSEC_DIR_INVALID; |
1adaa02b TB |
807 | } |
808 | } | |
809 | ||
17927ca6 TB |
810 | /** |
811 | * convert the policy type to the one defined in ipsec.h | |
812 | */ | |
b12c53ce | 813 | static inline uint16_t type2kernel(policy_type_t type) |
17927ca6 TB |
814 | { |
815 | switch (type) | |
816 | { | |
817 | case POLICY_IPSEC: | |
818 | return IPSEC_POLICY_IPSEC; | |
819 | case POLICY_PASS: | |
820 | return IPSEC_POLICY_NONE; | |
821 | case POLICY_DROP: | |
822 | return IPSEC_POLICY_DISCARD; | |
823 | } | |
824 | return type; | |
825 | } | |
826 | ||
d24a74c5 | 827 | #ifdef SADB_X_MIGRATE |
5145ae48 AS |
828 | /** |
829 | * convert the policy direction in ipsec.h to the general one. | |
830 | */ | |
b12c53ce | 831 | static policy_dir_t kernel2dir(uint8_t dir) |
5145ae48 AS |
832 | { |
833 | switch (dir) | |
834 | { | |
835 | case IPSEC_DIR_INBOUND: | |
836 | return POLICY_IN; | |
837 | case IPSEC_DIR_OUTBOUND: | |
838 | return POLICY_OUT; | |
617e59b7 | 839 | #ifdef HAVE_IPSEC_DIR_FWD |
5145ae48 AS |
840 | case IPSEC_DIR_FWD: |
841 | return POLICY_FWD; | |
d24a74c5 | 842 | #endif |
5145ae48 AS |
843 | default: |
844 | return dir; | |
845 | } | |
846 | } | |
d24a74c5 TB |
847 | #endif /*SADB_X_MIGRATE*/ |
848 | ||
1adaa02b TB |
849 | typedef struct kernel_algorithm_t kernel_algorithm_t; |
850 | ||
851 | /** | |
e517b4b1 | 852 | * Mapping of IKEv2 algorithms to PF_KEY algorithms |
1adaa02b TB |
853 | */ |
854 | struct kernel_algorithm_t { | |
855 | /** | |
856 | * Identifier specified in IKEv2 | |
857 | */ | |
e517b4b1 | 858 | int ikev2; |
7daf5226 | 859 | |
1adaa02b TB |
860 | /** |
861 | * Identifier as defined in pfkeyv2.h | |
862 | */ | |
e517b4b1 | 863 | int kernel; |
1adaa02b TB |
864 | }; |
865 | ||
866 | #define END_OF_LIST -1 | |
867 | ||
868 | /** | |
869 | * Algorithms for encryption | |
870 | */ | |
871 | static kernel_algorithm_t encryption_algs[] = { | |
d24a74c5 TB |
872 | /* {ENCR_DES_IV64, 0 }, */ |
873 | {ENCR_DES, SADB_EALG_DESCBC }, | |
874 | {ENCR_3DES, SADB_EALG_3DESCBC }, | |
875 | /* {ENCR_RC5, 0 }, */ | |
876 | /* {ENCR_IDEA, 0 }, */ | |
877 | {ENCR_CAST, SADB_X_EALG_CASTCBC }, | |
878 | {ENCR_BLOWFISH, SADB_X_EALG_BLOWFISHCBC }, | |
879 | /* {ENCR_3IDEA, 0 }, */ | |
880 | /* {ENCR_DES_IV32, 0 }, */ | |
881 | {ENCR_NULL, SADB_EALG_NULL }, | |
882 | {ENCR_AES_CBC, SADB_X_EALG_AESCBC }, | |
dff2d05b RB |
883 | #ifdef SADB_X_EALG_AESCTR |
884 | {ENCR_AES_CTR, SADB_X_EALG_AESCTR }, | |
885 | #endif | |
e526d228 AS |
886 | /* {ENCR_AES_CCM_ICV8, SADB_X_EALG_AES_CCM_ICV8 }, */ |
887 | /* {ENCR_AES_CCM_ICV12, SADB_X_EALG_AES_CCM_ICV12 }, */ | |
888 | /* {ENCR_AES_CCM_ICV16, SADB_X_EALG_AES_CCM_ICV16 }, */ | |
e2a252a8 TB |
889 | #ifdef SADB_X_EALG_AES_GCM_ICV8 /* assume the others are defined too */ |
890 | {ENCR_AES_GCM_ICV8, SADB_X_EALG_AES_GCM_ICV8 }, | |
891 | {ENCR_AES_GCM_ICV12, SADB_X_EALG_AES_GCM_ICV12 }, | |
892 | {ENCR_AES_GCM_ICV16, SADB_X_EALG_AES_GCM_ICV16 }, | |
e2b8c7e6 RT |
893 | #elif defined(SADB_X_EALG_AES_GCM) /* macOS */ |
894 | {ENCR_AES_GCM_ICV16, SADB_X_EALG_AES_GCM }, | |
b6759096 TB |
895 | #endif |
896 | #ifdef SADB_X_EALG_CAMELLIACBC | |
897 | {ENCR_CAMELLIA_CBC, SADB_X_EALG_CAMELLIACBC }, | |
e2a252a8 | 898 | #endif |
d24a74c5 | 899 | {END_OF_LIST, 0 }, |
1adaa02b TB |
900 | }; |
901 | ||
902 | /** | |
903 | * Algorithms for integrity protection | |
904 | */ | |
905 | static kernel_algorithm_t integrity_algs[] = { | |
d24a74c5 | 906 | {AUTH_HMAC_MD5_96, SADB_AALG_MD5HMAC }, |
e517b4b1 MW |
907 | {AUTH_HMAC_SHA1_96, SADB_AALG_SHA1HMAC }, |
908 | {AUTH_HMAC_SHA2_256_128, SADB_X_AALG_SHA2_256HMAC }, | |
909 | {AUTH_HMAC_SHA2_384_192, SADB_X_AALG_SHA2_384HMAC }, | |
910 | {AUTH_HMAC_SHA2_512_256, SADB_X_AALG_SHA2_512HMAC }, | |
911 | /* {AUTH_DES_MAC, 0, }, */ | |
912 | /* {AUTH_KPDK_MD5, 0, }, */ | |
7cdb1ddf | 913 | #ifdef SADB_X_AALG_AES_XCBC_MAC |
e517b4b1 | 914 | {AUTH_AES_XCBC_96, SADB_X_AALG_AES_XCBC_MAC, }, |
7cdb1ddf | 915 | #endif |
d24a74c5 | 916 | {END_OF_LIST, 0, }, |
1adaa02b TB |
917 | }; |
918 | ||
919 | /** | |
3d2dbebd | 920 | * Algorithms for IPComp, unused yet |
1adaa02b TB |
921 | */ |
922 | static kernel_algorithm_t compression_algs[] = { | |
d24a74c5 | 923 | /* {IPCOMP_OUI, 0 }, */ |
e517b4b1 | 924 | {IPCOMP_DEFLATE, SADB_X_CALG_DEFLATE }, |
6afa7761 | 925 | #ifdef SADB_X_CALG_LZS |
e517b4b1 | 926 | {IPCOMP_LZS, SADB_X_CALG_LZS }, |
6afa7761 FK |
927 | #endif |
928 | #ifdef SADB_X_CALG_LZJH | |
e517b4b1 | 929 | {IPCOMP_LZJH, SADB_X_CALG_LZJH }, |
6afa7761 | 930 | #endif |
d24a74c5 | 931 | {END_OF_LIST, 0 }, |
1adaa02b TB |
932 | }; |
933 | ||
934 | /** | |
935 | * Look up a kernel algorithm ID and its key size | |
936 | */ | |
08ad639f | 937 | static int lookup_algorithm(transform_type_t type, int ikev2) |
1adaa02b | 938 | { |
08ad639f | 939 | kernel_algorithm_t *list; |
b12c53ce | 940 | uint16_t alg = 0; |
08ad639f TB |
941 | |
942 | switch (type) | |
943 | { | |
944 | case ENCRYPTION_ALGORITHM: | |
945 | list = encryption_algs; | |
946 | break; | |
947 | case INTEGRITY_ALGORITHM: | |
948 | list = integrity_algs; | |
949 | break; | |
6afa7761 FK |
950 | case COMPRESSION_ALGORITHM: |
951 | list = compression_algs; | |
952 | break; | |
08ad639f TB |
953 | default: |
954 | return 0; | |
955 | } | |
e517b4b1 | 956 | while (list->ikev2 != END_OF_LIST) |
1adaa02b | 957 | { |
e517b4b1 | 958 | if (ikev2 == list->ikev2) |
1adaa02b | 959 | { |
e517b4b1 | 960 | return list->kernel; |
1adaa02b | 961 | } |
e517b4b1 | 962 | list++; |
1adaa02b | 963 | } |
8394ea2a | 964 | charon->kernel->lookup_algorithm(charon->kernel, ikev2, type, &alg, NULL); |
08ad639f | 965 | return alg; |
1adaa02b TB |
966 | } |
967 | ||
59213396 TB |
968 | /** |
969 | * Helper to set a port in a sockaddr_t, the port has to be in host order | |
970 | */ | |
b12c53ce | 971 | static void set_port(sockaddr_t *addr, uint16_t port) |
59213396 TB |
972 | { |
973 | switch (addr->sa_family) | |
974 | { | |
975 | case AF_INET: | |
976 | { | |
977 | struct sockaddr_in *sin = (struct sockaddr_in*)addr; | |
978 | sin->sin_port = htons(port); | |
979 | break; | |
980 | } | |
981 | case AF_INET6: | |
982 | { | |
983 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr; | |
984 | sin6->sin6_port = htons(port); | |
985 | break; | |
986 | } | |
987 | } | |
988 | } | |
989 | ||
1adaa02b | 990 | /** |
9041c074 | 991 | * Copy a host_t as sockaddr_t to the given memory location. |
668e84d9 | 992 | * @return the number of bytes copied |
1adaa02b | 993 | */ |
9041c074 | 994 | static size_t hostcpy(void *dest, host_t *host, bool include_port) |
1adaa02b | 995 | { |
668e84d9 | 996 | sockaddr_t *addr = host->get_sockaddr(host), *dest_addr = dest; |
1adaa02b | 997 | socklen_t *len = host->get_sockaddr_len(host); |
9041c074 | 998 | |
668e84d9 | 999 | memcpy(dest, addr, *len); |
d24a74c5 | 1000 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
668e84d9 | 1001 | dest_addr->sa_len = *len; |
d24a74c5 | 1002 | #endif |
59213396 | 1003 | if (!include_port) |
668e84d9 | 1004 | { |
59213396 | 1005 | set_port(dest_addr, 0); |
668e84d9 TB |
1006 | } |
1007 | return *len; | |
1008 | } | |
1009 | ||
f55a7a76 TB |
1010 | /** |
1011 | * add a host to the given sadb_msg | |
1012 | */ | |
b12c53ce AS |
1013 | static void add_addr_ext(struct sadb_msg *msg, host_t *host, uint16_t type, |
1014 | uint8_t proto, uint8_t prefixlen, bool include_port) | |
f55a7a76 TB |
1015 | { |
1016 | struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg); | |
59213396 TB |
1017 | size_t len; |
1018 | ||
f55a7a76 TB |
1019 | addr->sadb_address_exttype = type; |
1020 | addr->sadb_address_proto = proto; | |
1021 | addr->sadb_address_prefixlen = prefixlen; | |
d34a82dd | 1022 | len = hostcpy(addr + 1, host, include_port); |
59213396 | 1023 | addr->sadb_address_len = PFKEY_LEN(sizeof(*addr) + len); |
f55a7a76 TB |
1024 | PFKEY_EXT_ADD(msg, addr); |
1025 | } | |
1026 | ||
d24a74c5 | 1027 | #ifdef HAVE_NATT |
1adaa02b TB |
1028 | /** |
1029 | * add udp encap extensions to a sadb_msg | |
1030 | */ | |
1031 | static void add_encap_ext(struct sadb_msg *msg, host_t *src, host_t *dst) | |
1032 | { | |
1033 | struct sadb_x_nat_t_type* nat_type; | |
1034 | struct sadb_x_nat_t_port* nat_port; | |
7daf5226 | 1035 | |
1adaa02b TB |
1036 | nat_type = (struct sadb_x_nat_t_type*)PFKEY_EXT_ADD_NEXT(msg); |
1037 | nat_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; | |
108357b1 | 1038 | nat_type->sadb_x_nat_t_type_len = PFKEY_LEN(sizeof(*nat_type)); |
1adaa02b TB |
1039 | nat_type->sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP; |
1040 | PFKEY_EXT_ADD(msg, nat_type); | |
7daf5226 | 1041 | |
1adaa02b TB |
1042 | nat_port = (struct sadb_x_nat_t_port*)PFKEY_EXT_ADD_NEXT(msg); |
1043 | nat_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; | |
108357b1 | 1044 | nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(*nat_port)); |
1adaa02b TB |
1045 | nat_port->sadb_x_nat_t_port_port = htons(src->get_port(src)); |
1046 | PFKEY_EXT_ADD(msg, nat_port); | |
7daf5226 | 1047 | |
1adaa02b TB |
1048 | nat_port = (struct sadb_x_nat_t_port*)PFKEY_EXT_ADD_NEXT(msg); |
1049 | nat_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; | |
108357b1 | 1050 | nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(*nat_port)); |
1adaa02b TB |
1051 | nat_port->sadb_x_nat_t_port_port = htons(dst->get_port(dst)); |
1052 | PFKEY_EXT_ADD(msg, nat_port); | |
1053 | } | |
d24a74c5 | 1054 | #endif /*HAVE_NATT*/ |
1adaa02b | 1055 | |
e526d228 AS |
1056 | /** |
1057 | * Convert a sadb_address to a traffic_selector | |
1058 | */ | |
1059 | static traffic_selector_t* sadb_address2ts(struct sadb_address *address) | |
1060 | { | |
1061 | traffic_selector_t *ts; | |
e526d228 | 1062 | host_t *host; |
b12c53ce | 1063 | uint8_t proto; |
a9f14ada TB |
1064 | |
1065 | proto = address->sadb_address_proto; | |
1066 | proto = proto == IPSEC_PROTO_ANY ? 0 : proto; | |
e526d228 AS |
1067 | |
1068 | /* The Linux 2.6 kernel does not set the protocol and port information | |
323f9f99 MW |
1069 | * in the src and dst sadb_address extensions of the SADB_ACQUIRE message. |
1070 | */ | |
108357b1 TB |
1071 | host = host_create_from_sockaddr((sockaddr_t*)&address[1]); |
1072 | ts = traffic_selector_create_from_subnet(host, | |
1073 | address->sadb_address_prefixlen, | |
a9f14ada | 1074 | proto, host->get_port(host), |
a1db77de | 1075 | host->get_port(host) ?: 65535); |
e526d228 AS |
1076 | return ts; |
1077 | } | |
1078 | ||
1adaa02b TB |
1079 | /** |
1080 | * Parses a pfkey message received from the kernel | |
1081 | */ | |
1082 | static status_t parse_pfkey_message(struct sadb_msg *msg, pfkey_msg_t *out) | |
1083 | { | |
1084 | struct sadb_ext* ext; | |
1085 | size_t len; | |
7daf5226 | 1086 | |
1adaa02b TB |
1087 | memset(out, 0, sizeof(pfkey_msg_t)); |
1088 | out->msg = msg; | |
7daf5226 | 1089 | |
1adaa02b TB |
1090 | len = msg->sadb_msg_len; |
1091 | len -= PFKEY_LEN(sizeof(struct sadb_msg)); | |
7daf5226 | 1092 | |
1adaa02b | 1093 | ext = (struct sadb_ext*)(((char*)msg) + sizeof(struct sadb_msg)); |
7daf5226 | 1094 | |
1adaa02b TB |
1095 | while (len >= PFKEY_LEN(sizeof(struct sadb_ext))) |
1096 | { | |
bfca7aa5 | 1097 | DBG3(DBG_KNL, " %N", sadb_ext_type_names, ext->sadb_ext_type); |
1adaa02b TB |
1098 | if (ext->sadb_ext_len < PFKEY_LEN(sizeof(struct sadb_ext)) || |
1099 | ext->sadb_ext_len > len) | |
1100 | { | |
e526d228 AS |
1101 | DBG1(DBG_KNL, "length of %N extension is invalid", |
1102 | sadb_ext_type_names, ext->sadb_ext_type); | |
1adaa02b TB |
1103 | break; |
1104 | } | |
7daf5226 | 1105 | |
1adaa02b TB |
1106 | if ((ext->sadb_ext_type > SADB_EXT_MAX) || (!ext->sadb_ext_type)) |
1107 | { | |
108357b1 TB |
1108 | DBG1(DBG_KNL, "type of PF_KEY extension (%d) is invalid", |
1109 | ext->sadb_ext_type); | |
1adaa02b TB |
1110 | break; |
1111 | } | |
7daf5226 | 1112 | |
1adaa02b TB |
1113 | if (out->ext[ext->sadb_ext_type]) |
1114 | { | |
d24a74c5 | 1115 | DBG1(DBG_KNL, "duplicate %N extension", |
e526d228 | 1116 | sadb_ext_type_names, ext->sadb_ext_type); |
1adaa02b TB |
1117 | break; |
1118 | } | |
7daf5226 | 1119 | |
1adaa02b TB |
1120 | out->ext[ext->sadb_ext_type] = ext; |
1121 | ext = PFKEY_EXT_NEXT_LEN(ext, len); | |
1122 | } | |
1123 | ||
1124 | if (len) | |
1125 | { | |
1126 | DBG1(DBG_KNL, "PF_KEY message length is invalid"); | |
1127 | return FAILED; | |
1128 | } | |
7daf5226 | 1129 | |
1adaa02b TB |
1130 | return SUCCESS; |
1131 | } | |
1132 | ||
1133 | /** | |
1134 | * Send a message to a specific PF_KEY socket and handle the response. | |
1135 | */ | |
1136 | static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket, | |
1137 | struct sadb_msg *in, struct sadb_msg **out, size_t *out_len) | |
1138 | { | |
1139 | unsigned char buf[PFKEY_BUFFER_SIZE]; | |
1140 | struct sadb_msg *msg; | |
1141 | int in_len, len; | |
7daf5226 | 1142 | |
3ac5a0db | 1143 | this->mutex_pfkey->lock(this->mutex_pfkey); |
1adaa02b | 1144 | |
56ee8fcc TB |
1145 | /* FIXME: our usage of sequence numbers is probably wrong. check RFC 2367, |
1146 | * in particular the behavior in response to an SADB_ACQUIRE. */ | |
1adaa02b TB |
1147 | in->sadb_msg_seq = ++this->seq; |
1148 | in->sadb_msg_pid = getpid(); | |
1149 | ||
1150 | in_len = PFKEY_USER_LEN(in->sadb_msg_len); | |
1151 | ||
1152 | while (TRUE) | |
1153 | { | |
1154 | len = send(socket, in, in_len, 0); | |
1155 | ||
1156 | if (len != in_len) | |
1157 | { | |
1158 | if (errno == EINTR) | |
1159 | { | |
1160 | /* interrupted, try again */ | |
1161 | continue; | |
1162 | } | |
3ac5a0db | 1163 | this->mutex_pfkey->unlock(this->mutex_pfkey); |
108357b1 TB |
1164 | DBG1(DBG_KNL, "error sending to PF_KEY socket: %s", |
1165 | strerror(errno)); | |
1adaa02b TB |
1166 | return FAILED; |
1167 | } | |
1168 | break; | |
1169 | } | |
7daf5226 | 1170 | |
1adaa02b | 1171 | while (TRUE) |
d24a74c5 | 1172 | { |
1adaa02b | 1173 | msg = (struct sadb_msg*)buf; |
7daf5226 | 1174 | |
1adaa02b | 1175 | len = recv(socket, buf, sizeof(buf), 0); |
7daf5226 | 1176 | |
1adaa02b TB |
1177 | if (len < 0) |
1178 | { | |
1179 | if (errno == EINTR) | |
1180 | { | |
1181 | DBG1(DBG_KNL, "got interrupted"); | |
1182 | /* interrupted, try again */ | |
1183 | continue; | |
1184 | } | |
108357b1 TB |
1185 | DBG1(DBG_KNL, "error reading from PF_KEY socket: %s", |
1186 | strerror(errno)); | |
3ac5a0db | 1187 | this->mutex_pfkey->unlock(this->mutex_pfkey); |
1adaa02b TB |
1188 | return FAILED; |
1189 | } | |
1190 | if (len < sizeof(struct sadb_msg) || | |
1191 | msg->sadb_msg_len < PFKEY_LEN(sizeof(struct sadb_msg))) | |
1192 | { | |
1193 | DBG1(DBG_KNL, "received corrupted PF_KEY message"); | |
3ac5a0db | 1194 | this->mutex_pfkey->unlock(this->mutex_pfkey); |
1adaa02b TB |
1195 | return FAILED; |
1196 | } | |
1197 | if (msg->sadb_msg_len > len / PFKEY_ALIGNMENT) | |
1198 | { | |
108357b1 TB |
1199 | DBG1(DBG_KNL, "buffer was too small to receive the complete PF_KEY " |
1200 | "message"); | |
3ac5a0db | 1201 | this->mutex_pfkey->unlock(this->mutex_pfkey); |
1adaa02b TB |
1202 | return FAILED; |
1203 | } | |
1204 | if (msg->sadb_msg_pid != in->sadb_msg_pid) | |
1205 | { | |
1206 | DBG2(DBG_KNL, "received PF_KEY message is not intended for us"); | |
1207 | continue; | |
1208 | } | |
1209 | if (msg->sadb_msg_seq != this->seq) | |
1210 | { | |
470aad7e | 1211 | DBG2(DBG_KNL, "received PF_KEY message with unexpected sequence " |
108357b1 TB |
1212 | "number, was %d expected %d", msg->sadb_msg_seq, |
1213 | this->seq); | |
56ee8fcc TB |
1214 | if (msg->sadb_msg_seq == 0) |
1215 | { | |
1216 | /* FreeBSD and Mac OS X do this for the response to | |
1217 | * SADB_X_SPDGET (but not for the response to SADB_GET). | |
1218 | * FreeBSD: 'key_spdget' in /usr/src/sys/netipsec/key.c. */ | |
1219 | } | |
1220 | else if (msg->sadb_msg_seq < this->seq) | |
1adaa02b TB |
1221 | { |
1222 | continue; | |
1223 | } | |
56ee8fcc TB |
1224 | else |
1225 | { | |
1226 | this->mutex_pfkey->unlock(this->mutex_pfkey); | |
1227 | return FAILED; | |
1228 | } | |
1adaa02b TB |
1229 | } |
1230 | if (msg->sadb_msg_type != in->sadb_msg_type) | |
1231 | { | |
1232 | DBG2(DBG_KNL, "received PF_KEY message of wrong type, " | |
108357b1 TB |
1233 | "was %d expected %d, ignoring", msg->sadb_msg_type, |
1234 | in->sadb_msg_type); | |
1adaa02b TB |
1235 | } |
1236 | break; | |
1237 | } | |
7daf5226 | 1238 | |
1adaa02b TB |
1239 | *out_len = len; |
1240 | *out = (struct sadb_msg*)malloc(len); | |
1241 | memcpy(*out, buf, len); | |
7daf5226 | 1242 | |
3ac5a0db | 1243 | this->mutex_pfkey->unlock(this->mutex_pfkey); |
1adaa02b TB |
1244 | return SUCCESS; |
1245 | } | |
1246 | ||
1247 | /** | |
1248 | * Send a message to the default PF_KEY socket and handle the response. | |
1249 | */ | |
1250 | static status_t pfkey_send(private_kernel_pfkey_ipsec_t *this, | |
108357b1 TB |
1251 | struct sadb_msg *in, struct sadb_msg **out, |
1252 | size_t *out_len) | |
1adaa02b TB |
1253 | { |
1254 | return pfkey_send_socket(this, this->socket, in, out, out_len); | |
1255 | } | |
1256 | ||
1257 | /** | |
1258 | * Process a SADB_ACQUIRE message from the kernel | |
1259 | */ | |
108357b1 TB |
1260 | static void process_acquire(private_kernel_pfkey_ipsec_t *this, |
1261 | struct sadb_msg* msg) | |
1adaa02b TB |
1262 | { |
1263 | pfkey_msg_t response; | |
b12c53ce | 1264 | uint32_t index, reqid = 0; |
e526d228 | 1265 | traffic_selector_t *src_ts, *dst_ts; |
1adaa02b | 1266 | policy_entry_t *policy; |
17927ca6 | 1267 | policy_sa_t *sa; |
7daf5226 | 1268 | |
1adaa02b TB |
1269 | switch (msg->sadb_msg_satype) |
1270 | { | |
1271 | case SADB_SATYPE_UNSPEC: | |
1272 | case SADB_SATYPE_ESP: | |
1273 | case SADB_SATYPE_AH: | |
1274 | break; | |
1275 | default: | |
1276 | /* acquire for AH/ESP only */ | |
1277 | return; | |
1278 | } | |
e526d228 | 1279 | DBG2(DBG_KNL, "received an SADB_ACQUIRE"); |
7daf5226 | 1280 | |
1adaa02b TB |
1281 | if (parse_pfkey_message(msg, &response) != SUCCESS) |
1282 | { | |
1283 | DBG1(DBG_KNL, "parsing SADB_ACQUIRE from kernel failed"); | |
1284 | return; | |
1285 | } | |
7daf5226 | 1286 | |
1adaa02b | 1287 | index = response.x_policy->sadb_x_policy_id; |
3ac5a0db | 1288 | this->mutex->lock(this->mutex); |
2e4d110d TB |
1289 | if (this->policies->find_first(this->policies, policy_entry_match_byindex, |
1290 | (void**)&policy, index) && | |
17927ca6 | 1291 | policy->used_by->get_first(policy->used_by, (void**)&sa) == SUCCESS) |
1adaa02b | 1292 | { |
17927ca6 | 1293 | reqid = sa->sa->cfg.reqid; |
e526d228 AS |
1294 | } |
1295 | else | |
1296 | { | |
108357b1 TB |
1297 | DBG1(DBG_KNL, "received an SADB_ACQUIRE with policy id %d but no " |
1298 | "matching policy found", index); | |
1adaa02b | 1299 | } |
108357b1 TB |
1300 | this->mutex->unlock(this->mutex); |
1301 | ||
e526d228 AS |
1302 | src_ts = sadb_address2ts(response.src); |
1303 | dst_ts = sadb_address2ts(response.dst); | |
7daf5226 | 1304 | |
8394ea2a | 1305 | charon->kernel->acquire(charon->kernel, reqid, src_ts, dst_ts); |
1adaa02b TB |
1306 | } |
1307 | ||
1308 | /** | |
1309 | * Process a SADB_EXPIRE message from the kernel | |
1310 | */ | |
108357b1 TB |
1311 | static void process_expire(private_kernel_pfkey_ipsec_t *this, |
1312 | struct sadb_msg* msg) | |
1adaa02b TB |
1313 | { |
1314 | pfkey_msg_t response; | |
b12c53ce AS |
1315 | uint8_t protocol; |
1316 | uint32_t spi; | |
f81a9497 | 1317 | host_t *dst; |
1adaa02b | 1318 | bool hard; |
7daf5226 | 1319 | |
1adaa02b | 1320 | DBG2(DBG_KNL, "received an SADB_EXPIRE"); |
7daf5226 | 1321 | |
1adaa02b TB |
1322 | if (parse_pfkey_message(msg, &response) != SUCCESS) |
1323 | { | |
1324 | DBG1(DBG_KNL, "parsing SADB_EXPIRE from kernel failed"); | |
1325 | return; | |
1326 | } | |
7daf5226 | 1327 | |
9f166d9a | 1328 | protocol = satype2proto(msg->sadb_msg_satype); |
1adaa02b | 1329 | spi = response.sa->sadb_sa_spi; |
1adaa02b | 1330 | hard = response.lft_hard != NULL; |
7daf5226 | 1331 | |
f81a9497 | 1332 | if (protocol == IPPROTO_ESP || protocol == IPPROTO_AH) |
1adaa02b | 1333 | { |
f81a9497 MW |
1334 | dst = host_create_from_sockaddr((sockaddr_t*)(response.dst + 1)); |
1335 | if (dst) | |
1336 | { | |
8394ea2a | 1337 | charon->kernel->expire(charon->kernel, protocol, spi, dst, hard); |
f81a9497 MW |
1338 | dst->destroy(dst); |
1339 | } | |
1adaa02b | 1340 | } |
1adaa02b TB |
1341 | } |
1342 | ||
d24a74c5 | 1343 | #ifdef SADB_X_MIGRATE |
e526d228 | 1344 | /** |
d24a74c5 | 1345 | * Process a SADB_X_MIGRATE message from the kernel |
e526d228 | 1346 | */ |
108357b1 TB |
1347 | static void process_migrate(private_kernel_pfkey_ipsec_t *this, |
1348 | struct sadb_msg* msg) | |
e526d228 AS |
1349 | { |
1350 | pfkey_msg_t response; | |
5145ae48 AS |
1351 | traffic_selector_t *src_ts, *dst_ts; |
1352 | policy_dir_t dir; | |
b12c53ce | 1353 | uint32_t reqid = 0; |
f11a54bc | 1354 | host_t *local = NULL, *remote = NULL; |
e526d228 AS |
1355 | |
1356 | DBG2(DBG_KNL, "received an SADB_X_MIGRATE"); | |
1357 | ||
1358 | if (parse_pfkey_message(msg, &response) != SUCCESS) | |
1359 | { | |
1360 | DBG1(DBG_KNL, "parsing SADB_X_MIGRATE from kernel failed"); | |
1361 | return; | |
1362 | } | |
5145ae48 AS |
1363 | src_ts = sadb_address2ts(response.src); |
1364 | dst_ts = sadb_address2ts(response.dst); | |
5145ae48 AS |
1365 | dir = kernel2dir(response.x_policy->sadb_x_policy_dir); |
1366 | DBG2(DBG_KNL, " policy %R === %R %N, id %u", src_ts, dst_ts, | |
7a915d62 | 1367 | policy_dir_names, dir); |
7daf5226 | 1368 | |
d24a74c5 | 1369 | /* SADB_X_EXT_KMADDRESS is not present in unpatched kernels < 2.6.28 */ |
f11a54bc AS |
1370 | if (response.x_kmaddress) |
1371 | { | |
1372 | sockaddr_t *local_addr, *remote_addr; | |
b12c53ce | 1373 | uint32_t local_len; |
f11a54bc AS |
1374 | |
1375 | local_addr = (sockaddr_t*)&response.x_kmaddress[1]; | |
1376 | local = host_create_from_sockaddr(local_addr); | |
1377 | local_len = (local_addr->sa_family == AF_INET6)? | |
1378 | sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); | |
b12c53ce | 1379 | remote_addr = (sockaddr_t*)((uint8_t*)local_addr + local_len); |
f11a54bc AS |
1380 | remote = host_create_from_sockaddr(remote_addr); |
1381 | DBG2(DBG_KNL, " kmaddress: %H...%H", local, remote); | |
1382 | } | |
7daf5226 | 1383 | |
7a915d62 | 1384 | if (src_ts && dst_ts && local && remote) |
ef6d339c | 1385 | { |
8394ea2a TB |
1386 | charon->kernel->migrate(charon->kernel, reqid, src_ts, dst_ts, dir, |
1387 | local, remote); | |
ef6d339c AS |
1388 | } |
1389 | else | |
1390 | { | |
1391 | DESTROY_IF(src_ts); | |
1392 | DESTROY_IF(dst_ts); | |
1393 | DESTROY_IF(local); | |
2c815393 | 1394 | DESTROY_IF(remote); |
ef6d339c | 1395 | } |
e526d228 | 1396 | } |
d24a74c5 | 1397 | #endif /*SADB_X_MIGRATE*/ |
e526d228 | 1398 | |
ed76b216 | 1399 | #ifdef SADB_X_NAT_T_NEW_MAPPING |
1adaa02b TB |
1400 | /** |
1401 | * Process a SADB_X_NAT_T_NEW_MAPPING message from the kernel | |
1402 | */ | |
108357b1 TB |
1403 | static void process_mapping(private_kernel_pfkey_ipsec_t *this, |
1404 | struct sadb_msg* msg) | |
1adaa02b TB |
1405 | { |
1406 | pfkey_msg_t response; | |
b12c53ce | 1407 | uint32_t spi; |
108357b1 | 1408 | sockaddr_t *sa; |
b125839a | 1409 | host_t *dst, *new; |
7daf5226 | 1410 | |
1adaa02b | 1411 | DBG2(DBG_KNL, "received an SADB_X_NAT_T_NEW_MAPPING"); |
7daf5226 | 1412 | |
1adaa02b TB |
1413 | if (parse_pfkey_message(msg, &response) != SUCCESS) |
1414 | { | |
1415 | DBG1(DBG_KNL, "parsing SADB_X_NAT_T_NEW_MAPPING from kernel failed"); | |
1416 | return; | |
1417 | } | |
7daf5226 | 1418 | |
1adaa02b TB |
1419 | if (!response.x_sa2) |
1420 | { | |
01563352 TB |
1421 | DBG1(DBG_KNL, "received SADB_X_NAT_T_NEW_MAPPING is missing required " |
1422 | "information"); | |
1adaa02b TB |
1423 | return; |
1424 | } | |
7daf5226 | 1425 | |
1adaa02b | 1426 | spi = response.sa->sadb_sa_spi; |
7daf5226 | 1427 | |
108357b1 TB |
1428 | if (satype2proto(msg->sadb_msg_satype) != IPPROTO_ESP) |
1429 | { | |
1430 | return; | |
1431 | } | |
1432 | ||
1433 | sa = (sockaddr_t*)(response.dst + 1); | |
b125839a | 1434 | dst = host_create_from_sockaddr(sa); |
108357b1 | 1435 | switch (sa->sa_family) |
1adaa02b | 1436 | { |
108357b1 | 1437 | case AF_INET: |
1adaa02b | 1438 | { |
108357b1 TB |
1439 | struct sockaddr_in *sin = (struct sockaddr_in*)sa; |
1440 | sin->sin_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port); | |
9ff9c3d1 | 1441 | break; |
1adaa02b | 1442 | } |
108357b1 | 1443 | case AF_INET6: |
1adaa02b | 1444 | { |
108357b1 TB |
1445 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; |
1446 | sin6->sin6_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port); | |
9ff9c3d1 | 1447 | break; |
1adaa02b | 1448 | } |
108357b1 TB |
1449 | default: |
1450 | break; | |
1451 | } | |
b125839a | 1452 | if (dst) |
108357b1 | 1453 | { |
b125839a MW |
1454 | new = host_create_from_sockaddr(sa); |
1455 | if (new) | |
1456 | { | |
8394ea2a | 1457 | charon->kernel->mapping(charon->kernel, IPPROTO_ESP, spi, dst, new); |
b125839a MW |
1458 | new->destroy(new); |
1459 | } | |
1460 | dst->destroy(dst); | |
1adaa02b TB |
1461 | } |
1462 | } | |
ed76b216 | 1463 | #endif /*SADB_X_NAT_T_NEW_MAPPING*/ |
1adaa02b TB |
1464 | |
1465 | /** | |
1466 | * Receives events from kernel | |
1467 | */ | |
7f698dae MW |
1468 | static bool receive_events(private_kernel_pfkey_ipsec_t *this, int fd, |
1469 | watcher_event_t event) | |
1adaa02b TB |
1470 | { |
1471 | unsigned char buf[PFKEY_BUFFER_SIZE]; | |
1472 | struct sadb_msg *msg = (struct sadb_msg*)buf; | |
108357b1 | 1473 | int len; |
7daf5226 | 1474 | |
7f698dae | 1475 | len = recvfrom(this->socket_events, buf, sizeof(buf), MSG_DONTWAIT, NULL, 0); |
1adaa02b TB |
1476 | if (len < 0) |
1477 | { | |
1478 | switch (errno) | |
1479 | { | |
1480 | case EINTR: | |
1481 | /* interrupted, try again */ | |
7f698dae | 1482 | return TRUE; |
1adaa02b TB |
1483 | case EAGAIN: |
1484 | /* no data ready, select again */ | |
7f698dae | 1485 | return TRUE; |
1adaa02b TB |
1486 | default: |
1487 | DBG1(DBG_KNL, "unable to receive from PF_KEY event socket"); | |
1488 | sleep(1); | |
7f698dae | 1489 | return TRUE; |
1adaa02b TB |
1490 | } |
1491 | } | |
7daf5226 | 1492 | |
1adaa02b TB |
1493 | if (len < sizeof(struct sadb_msg) || |
1494 | msg->sadb_msg_len < PFKEY_LEN(sizeof(struct sadb_msg))) | |
1495 | { | |
1496 | DBG2(DBG_KNL, "received corrupted PF_KEY message"); | |
7f698dae | 1497 | return TRUE; |
1adaa02b TB |
1498 | } |
1499 | if (msg->sadb_msg_pid != 0) | |
1500 | { /* not from kernel. not interested, try another one */ | |
7f698dae | 1501 | return TRUE; |
1adaa02b TB |
1502 | } |
1503 | if (msg->sadb_msg_len > len / PFKEY_ALIGNMENT) | |
1504 | { | |
108357b1 TB |
1505 | DBG1(DBG_KNL, "buffer was too small to receive the complete " |
1506 | "PF_KEY message"); | |
7f698dae | 1507 | return TRUE; |
1adaa02b | 1508 | } |
7daf5226 | 1509 | |
1adaa02b TB |
1510 | switch (msg->sadb_msg_type) |
1511 | { | |
1512 | case SADB_ACQUIRE: | |
1513 | process_acquire(this, msg); | |
1514 | break; | |
1515 | case SADB_EXPIRE: | |
1516 | process_expire(this, msg); | |
1517 | break; | |
d24a74c5 | 1518 | #ifdef SADB_X_MIGRATE |
e526d228 AS |
1519 | case SADB_X_MIGRATE: |
1520 | process_migrate(this, msg); | |
1521 | break; | |
d24a74c5 | 1522 | #endif /*SADB_X_MIGRATE*/ |
ed76b216 | 1523 | #ifdef SADB_X_NAT_T_NEW_MAPPING |
1adaa02b TB |
1524 | case SADB_X_NAT_T_NEW_MAPPING: |
1525 | process_mapping(this, msg); | |
1526 | break; | |
ed76b216 | 1527 | #endif /*SADB_X_NAT_T_NEW_MAPPING*/ |
1adaa02b TB |
1528 | default: |
1529 | break; | |
1530 | } | |
7daf5226 | 1531 | |
7f698dae | 1532 | return TRUE; |
1adaa02b TB |
1533 | } |
1534 | ||
6afa7761 FK |
1535 | /** |
1536 | * Get an SPI for a specific protocol from the kernel. | |
1537 | */ | |
1538 | ||
1539 | static status_t get_spi_internal(private_kernel_pfkey_ipsec_t *this, | |
b12c53ce AS |
1540 | host_t *src, host_t *dst, uint8_t proto, uint32_t min, uint32_t max, |
1541 | uint32_t *spi) | |
1adaa02b TB |
1542 | { |
1543 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
1544 | struct sadb_msg *msg, *out; | |
1adaa02b TB |
1545 | struct sadb_spirange *range; |
1546 | pfkey_msg_t response; | |
b12c53ce | 1547 | uint32_t received_spi = 0; |
1adaa02b | 1548 | size_t len; |
7daf5226 | 1549 | |
1adaa02b | 1550 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1551 | |
1adaa02b TB |
1552 | msg = (struct sadb_msg*)request; |
1553 | msg->sadb_msg_version = PF_KEY_V2; | |
1554 | msg->sadb_msg_type = SADB_GETSPI; | |
6afa7761 | 1555 | msg->sadb_msg_satype = proto2satype(proto); |
1adaa02b | 1556 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); |
7daf5226 | 1557 | |
9041c074 TB |
1558 | add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); |
1559 | add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); | |
7daf5226 | 1560 | |
1adaa02b TB |
1561 | range = (struct sadb_spirange*)PFKEY_EXT_ADD_NEXT(msg); |
1562 | range->sadb_spirange_exttype = SADB_EXT_SPIRANGE; | |
1563 | range->sadb_spirange_len = PFKEY_LEN(sizeof(struct sadb_spirange)); | |
6afa7761 FK |
1564 | range->sadb_spirange_min = min; |
1565 | range->sadb_spirange_max = max; | |
1adaa02b | 1566 | PFKEY_EXT_ADD(msg, range); |
7daf5226 | 1567 | |
1adaa02b TB |
1568 | if (pfkey_send(this, msg, &out, &len) == SUCCESS) |
1569 | { | |
1570 | if (out->sadb_msg_errno) | |
1571 | { | |
1572 | DBG1(DBG_KNL, "allocating SPI failed: %s (%d)", | |
108357b1 | 1573 | strerror(out->sadb_msg_errno), out->sadb_msg_errno); |
1adaa02b TB |
1574 | } |
1575 | else if (parse_pfkey_message(out, &response) == SUCCESS) | |
1576 | { | |
1577 | received_spi = response.sa->sadb_sa_spi; | |
1578 | } | |
d24a74c5 | 1579 | free(out); |
1adaa02b | 1580 | } |
7daf5226 | 1581 | |
1adaa02b TB |
1582 | if (received_spi == 0) |
1583 | { | |
1584 | return FAILED; | |
1585 | } | |
7daf5226 | 1586 | |
1adaa02b TB |
1587 | *spi = received_spi; |
1588 | return SUCCESS; | |
1589 | } | |
1590 | ||
6afa7761 FK |
1591 | METHOD(kernel_ipsec_t, get_spi, status_t, |
1592 | private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, | |
b12c53ce | 1593 | uint8_t protocol, uint32_t *spi) |
6afa7761 | 1594 | { |
6d86d0f5 TB |
1595 | uint32_t spi_min, spi_max; |
1596 | ||
1597 | spi_min = lib->settings->get_int(lib->settings, "%s.spi_min", | |
1598 | KERNEL_SPI_MIN, lib->ns); | |
1599 | spi_max = lib->settings->get_int(lib->settings, "%s.spi_max", | |
1600 | KERNEL_SPI_MAX, lib->ns); | |
1601 | ||
1602 | if (get_spi_internal(this, src, dst, protocol, min(spi_min, spi_max), | |
1603 | max(spi_min, spi_max), spi) != SUCCESS) | |
6afa7761 | 1604 | { |
2a1c9e20 | 1605 | DBG1(DBG_KNL, "unable to get SPI"); |
6afa7761 FK |
1606 | return FAILED; |
1607 | } | |
1608 | ||
2a1c9e20 | 1609 | DBG2(DBG_KNL, "got SPI %.8x", ntohl(*spi)); |
6afa7761 FK |
1610 | return SUCCESS; |
1611 | } | |
1612 | ||
44791b75 MW |
1613 | METHOD(kernel_ipsec_t, get_cpi, status_t, |
1614 | private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, | |
b12c53ce | 1615 | uint16_t *cpi) |
1adaa02b | 1616 | { |
b12c53ce | 1617 | uint32_t received_spi = 0; |
6afa7761 | 1618 | |
2a1c9e20 | 1619 | DBG2(DBG_KNL, "getting CPI"); |
6afa7761 FK |
1620 | |
1621 | if (get_spi_internal(this, src, dst, IPPROTO_COMP, | |
2a1c9e20 | 1622 | 0x100, 0xEFFF, &received_spi) != SUCCESS) |
6afa7761 | 1623 | { |
2a1c9e20 | 1624 | DBG1(DBG_KNL, "unable to get CPI"); |
6afa7761 FK |
1625 | return FAILED; |
1626 | } | |
1627 | ||
b12c53ce | 1628 | *cpi = htons((uint16_t)ntohl(received_spi)); |
6afa7761 | 1629 | |
2a1c9e20 | 1630 | DBG2(DBG_KNL, "got CPI %.4x", ntohs(*cpi)); |
6afa7761 | 1631 | return SUCCESS; |
1adaa02b TB |
1632 | } |
1633 | ||
44791b75 | 1634 | METHOD(kernel_ipsec_t, add_sa, status_t, |
89da06ac TB |
1635 | private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id, |
1636 | kernel_ipsec_add_sa_t *data) | |
1adaa02b TB |
1637 | { |
1638 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
1639 | struct sadb_msg *msg, *out; | |
1640 | struct sadb_sa *sa; | |
1641 | struct sadb_x_sa2 *sa2; | |
1adaa02b TB |
1642 | struct sadb_lifetime *lft; |
1643 | struct sadb_key *key; | |
1644 | size_t len; | |
89da06ac TB |
1645 | uint16_t ipcomp = data->ipcomp; |
1646 | ipsec_mode_t mode = data->mode; | |
7daf5226 | 1647 | |
6afa7761 FK |
1648 | /* if IPComp is used, we install an additional IPComp SA. if the cpi is 0 |
1649 | * we are in the recursive call below */ | |
89da06ac | 1650 | if (ipcomp != IPCOMP_NONE && data->cpi != 0) |
6afa7761 FK |
1651 | { |
1652 | lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}}; | |
89da06ac TB |
1653 | kernel_ipsec_sa_id_t ipcomp_id = { |
1654 | .src = id->src, | |
1655 | .dst = id->dst, | |
1656 | .spi = htonl(ntohs(data->cpi)), | |
1657 | .proto = IPPROTO_COMP, | |
1658 | .mark = id->mark, | |
1659 | }; | |
1660 | kernel_ipsec_add_sa_t ipcomp_sa = { | |
1661 | .reqid = data->reqid, | |
1662 | .mode = data->mode, | |
1663 | .src_ts = data->src_ts, | |
1664 | .dst_ts = data->dst_ts, | |
1665 | .lifetime = &lft, | |
1666 | .enc_alg = ENCR_UNDEFINED, | |
1667 | .int_alg = AUTH_UNDEFINED, | |
1668 | .tfc = data->tfc, | |
1669 | .ipcomp = data->ipcomp, | |
1670 | .initiator = data->initiator, | |
1671 | .inbound = data->inbound, | |
1672 | .update = data->update, | |
1673 | }; | |
1674 | add_sa(this, &ipcomp_id, &ipcomp_sa); | |
6afa7761 FK |
1675 | ipcomp = IPCOMP_NONE; |
1676 | /* use transport mode ESP SA, IPComp uses tunnel mode */ | |
1677 | mode = MODE_TRANSPORT; | |
1678 | } | |
1679 | ||
89da06ac | 1680 | if (data->update) |
6ad787ca MW |
1681 | { |
1682 | /* As we didn't know the reqid during SPI allocation, we used reqid | |
1683 | * zero. Unfortunately we can't SADB_UPDATE to the new reqid, hence we | |
1684 | * have to delete the SPI allocation state manually. The reqid | |
1685 | * selector does not count for that, therefore we have to delete | |
1686 | * that state before installing the new SA to avoid deleting the | |
1687 | * the new state after installing it. */ | |
89da06ac TB |
1688 | kernel_ipsec_sa_id_t del_id = { |
1689 | .src = id->src, | |
1690 | .dst = id->dst, | |
1691 | .spi = id->spi, | |
1692 | .proto = id->proto, | |
1693 | }; | |
1694 | kernel_ipsec_del_sa_t del = { 0 }; | |
1695 | ||
1696 | if (this->public.interface.del_sa(&this->public.interface, &del_id, | |
1697 | &del) != SUCCESS) | |
6ad787ca MW |
1698 | { |
1699 | DBG1(DBG_KNL, "deleting SPI allocation SA failed"); | |
1700 | } | |
1701 | } | |
1702 | ||
1adaa02b | 1703 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1704 | |
108357b1 | 1705 | DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", |
89da06ac | 1706 | ntohl(id->spi), data->reqid); |
7daf5226 | 1707 | |
1adaa02b TB |
1708 | msg = (struct sadb_msg*)request; |
1709 | msg->sadb_msg_version = PF_KEY_V2; | |
6ad787ca | 1710 | msg->sadb_msg_type = SADB_ADD; |
89da06ac | 1711 | msg->sadb_msg_satype = proto2satype(id->proto); |
1adaa02b | 1712 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); |
e20bd8b6 TB |
1713 | |
1714 | #ifdef __APPLE__ | |
89da06ac | 1715 | if (data->encap) |
e20bd8b6 TB |
1716 | { |
1717 | struct sadb_sa_2 *sa_2; | |
1718 | sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg); | |
89da06ac | 1719 | sa_2->sadb_sa_natt_port = id->dst->get_port(id->dst); |
e20bd8b6 TB |
1720 | sa = &sa_2->sa; |
1721 | sa->sadb_sa_flags |= SADB_X_EXT_NATT; | |
1722 | len = sizeof(struct sadb_sa_2); | |
1723 | } | |
1724 | else | |
1725 | #endif | |
1726 | { | |
1727 | sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); | |
1728 | len = sizeof(struct sadb_sa); | |
1729 | } | |
1adaa02b | 1730 | sa->sadb_sa_exttype = SADB_EXT_SA; |
e20bd8b6 | 1731 | sa->sadb_sa_len = PFKEY_LEN(len); |
89da06ac | 1732 | sa->sadb_sa_spi = id->spi; |
4ae2209e | 1733 | sa->sadb_sa_state = SADB_SASTATE_MATURE; |
89da06ac | 1734 | if (id->proto == IPPROTO_COMP) |
6afa7761 | 1735 | { |
89da06ac TB |
1736 | sa->sadb_sa_encrypt = lookup_algorithm(COMPRESSION_ALGORITHM, |
1737 | ipcomp); | |
6afa7761 FK |
1738 | } |
1739 | else | |
1740 | { | |
d21b0146 | 1741 | /* Linux interprets sadb_sa_replay as number of packets/bits in the |
21aa9242 TB |
1742 | * replay window, whereas on BSD it's the size of the window in bytes. |
1743 | * Only set for the inbound SA as it's not relevant for the outbound | |
1744 | * SA and might waste memory with large windows. */ | |
1745 | if (data->inbound) | |
1746 | { | |
d21b0146 | 1747 | #ifdef __linux__ |
21aa9242 | 1748 | sa->sadb_sa_replay = min(data->replay_window, 32); |
d21b0146 | 1749 | #else |
88a8fba1 | 1750 | sa->sadb_sa_replay = min((data->replay_window + 7) / 8, UINT8_MAX); |
d21b0146 | 1751 | #endif |
21aa9242 | 1752 | } |
89da06ac TB |
1753 | sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, data->int_alg); |
1754 | sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, | |
1755 | data->enc_alg); | |
6afa7761 | 1756 | } |
1adaa02b | 1757 | PFKEY_EXT_ADD(msg, sa); |
7daf5226 | 1758 | |
88a8fba1 TB |
1759 | #ifdef SADB_X_EXT_SA_REPLAY |
1760 | if (data->inbound) | |
1761 | { | |
381f6d98 | 1762 | struct sadb_x_sa_replay *repl; |
88a8fba1 | 1763 | |
381f6d98 TB |
1764 | repl = (struct sadb_x_sa_replay*)PFKEY_EXT_ADD_NEXT(msg); |
1765 | repl->sadb_x_sa_replay_exttype = SADB_X_EXT_SA_REPLAY; | |
1766 | repl->sadb_x_sa_replay_len = PFKEY_LEN(sizeof(struct sadb_x_sa_replay)); | |
1767 | repl->sadb_x_sa_replay_replay = min(data->replay_window, UINT32_MAX-32); | |
1768 | PFKEY_EXT_ADD(msg, repl); | |
88a8fba1 TB |
1769 | } |
1770 | #endif | |
1771 | ||
1adaa02b TB |
1772 | sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg); |
1773 | sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2; | |
1774 | sa2->sadb_x_sa2_len = PFKEY_LEN(sizeof(struct sadb_spirange)); | |
1775 | sa2->sadb_x_sa2_mode = mode2kernel(mode); | |
89da06ac | 1776 | sa2->sadb_x_sa2_reqid = data->reqid; |
1adaa02b | 1777 | PFKEY_EXT_ADD(msg, sa2); |
7daf5226 | 1778 | |
89da06ac TB |
1779 | add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); |
1780 | add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); | |
7daf5226 | 1781 | |
1adaa02b TB |
1782 | lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); |
1783 | lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; | |
1784 | lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime)); | |
89da06ac TB |
1785 | lft->sadb_lifetime_allocations = data->lifetime->packets.rekey; |
1786 | lft->sadb_lifetime_bytes = data->lifetime->bytes.rekey; | |
1787 | lft->sadb_lifetime_addtime = data->lifetime->time.rekey; | |
1087b9ce | 1788 | lft->sadb_lifetime_usetime = 0; /* we only use addtime */ |
1adaa02b | 1789 | PFKEY_EXT_ADD(msg, lft); |
7daf5226 | 1790 | |
1adaa02b TB |
1791 | lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); |
1792 | lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; | |
1793 | lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime)); | |
89da06ac TB |
1794 | lft->sadb_lifetime_allocations = data->lifetime->packets.life; |
1795 | lft->sadb_lifetime_bytes = data->lifetime->bytes.life; | |
1796 | lft->sadb_lifetime_addtime = data->lifetime->time.life; | |
1087b9ce | 1797 | lft->sadb_lifetime_usetime = 0; /* we only use addtime */ |
1adaa02b | 1798 | PFKEY_EXT_ADD(msg, lft); |
7daf5226 | 1799 | |
89da06ac | 1800 | if (data->enc_alg != ENCR_UNDEFINED) |
1adaa02b TB |
1801 | { |
1802 | if (!sa->sadb_sa_encrypt) | |
1803 | { | |
1804 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", | |
89da06ac | 1805 | encryption_algorithm_names, data->enc_alg); |
1adaa02b TB |
1806 | return FAILED; |
1807 | } | |
1808 | DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", | |
89da06ac | 1809 | encryption_algorithm_names, data->enc_alg, data->enc_key.len * 8); |
7daf5226 | 1810 | |
1adaa02b TB |
1811 | key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg); |
1812 | key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; | |
89da06ac TB |
1813 | key->sadb_key_bits = data->enc_key.len * 8; |
1814 | key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + data->enc_key.len); | |
1815 | memcpy(key + 1, data->enc_key.ptr, data->enc_key.len); | |
7daf5226 | 1816 | |
1adaa02b TB |
1817 | PFKEY_EXT_ADD(msg, key); |
1818 | } | |
7daf5226 | 1819 | |
89da06ac | 1820 | if (data->int_alg != AUTH_UNDEFINED) |
1adaa02b TB |
1821 | { |
1822 | if (!sa->sadb_sa_auth) | |
1823 | { | |
1824 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", | |
89da06ac | 1825 | integrity_algorithm_names, data->int_alg); |
1adaa02b TB |
1826 | return FAILED; |
1827 | } | |
1828 | DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", | |
89da06ac | 1829 | integrity_algorithm_names, data->int_alg, data->int_key.len * 8); |
7daf5226 | 1830 | |
1adaa02b TB |
1831 | key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg); |
1832 | key->sadb_key_exttype = SADB_EXT_KEY_AUTH; | |
89da06ac TB |
1833 | key->sadb_key_bits = data->int_key.len * 8; |
1834 | key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + data->int_key.len); | |
1835 | memcpy(key + 1, data->int_key.ptr, data->int_key.len); | |
7daf5226 | 1836 | |
1adaa02b TB |
1837 | PFKEY_EXT_ADD(msg, key); |
1838 | } | |
7daf5226 | 1839 | |
d24a74c5 | 1840 | #ifdef HAVE_NATT |
89da06ac | 1841 | if (data->encap) |
1adaa02b | 1842 | { |
89da06ac | 1843 | add_encap_ext(msg, id->src, id->dst); |
1adaa02b | 1844 | } |
d24a74c5 | 1845 | #endif /*HAVE_NATT*/ |
7daf5226 | 1846 | |
1adaa02b TB |
1847 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) |
1848 | { | |
89da06ac TB |
1849 | DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", |
1850 | ntohl(id->spi)); | |
1adaa02b TB |
1851 | return FAILED; |
1852 | } | |
1853 | else if (out->sadb_msg_errno) | |
1854 | { | |
1855 | DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x: %s (%d)", | |
89da06ac TB |
1856 | ntohl(id->spi), strerror(out->sadb_msg_errno), |
1857 | out->sadb_msg_errno); | |
1adaa02b TB |
1858 | free(out); |
1859 | return FAILED; | |
1860 | } | |
7daf5226 | 1861 | |
1adaa02b TB |
1862 | free(out); |
1863 | return SUCCESS; | |
1864 | } | |
1865 | ||
44791b75 | 1866 | METHOD(kernel_ipsec_t, update_sa, status_t, |
89da06ac TB |
1867 | private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id, |
1868 | kernel_ipsec_update_sa_t *data) | |
1adaa02b TB |
1869 | { |
1870 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
1871 | struct sadb_msg *msg, *out; | |
1872 | struct sadb_sa *sa; | |
1adaa02b TB |
1873 | pfkey_msg_t response; |
1874 | size_t len; | |
7daf5226 | 1875 | |
bf08e394 | 1876 | #ifndef SADB_X_EXT_NEW_ADDRESS_SRC |
ea625fab TB |
1877 | /* we can't update the SA if any of the ip addresses have changed. |
1878 | * that's because we can't use SADB_UPDATE and by deleting and readding the | |
1879 | * SA the sequence numbers would get lost */ | |
89da06ac TB |
1880 | if (!id->src->ip_equals(id->src, data->new_src) || |
1881 | !id->dst->ip_equals(id->dst, data->new_dst)) | |
ea625fab | 1882 | { |
108357b1 | 1883 | DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: address " |
89da06ac | 1884 | "changes are not supported", ntohl(id->spi)); |
ea625fab TB |
1885 | return NOT_SUPPORTED; |
1886 | } | |
bf08e394 | 1887 | #endif /*SADB_X_EXT_NEW_ADDRESS_SRC*/ |
7daf5226 | 1888 | |
6afa7761 | 1889 | /* if IPComp is used, we first update the IPComp SA */ |
89da06ac TB |
1890 | if (data->cpi) |
1891 | { | |
1892 | kernel_ipsec_sa_id_t ipcomp_id = { | |
1893 | .src = id->src, | |
1894 | .dst = id->dst, | |
1895 | .spi = htonl(ntohs(data->cpi)), | |
1896 | .proto = IPPROTO_COMP, | |
1897 | .mark = id->mark, | |
1898 | }; | |
1899 | kernel_ipsec_update_sa_t ipcomp = { | |
1900 | .new_src = data->new_src, | |
1901 | .new_dst = data->new_dst, | |
1902 | }; | |
1903 | update_sa(this, &ipcomp_id, &ipcomp); | |
6afa7761 FK |
1904 | } |
1905 | ||
1adaa02b | 1906 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1907 | |
89da06ac TB |
1908 | DBG2(DBG_KNL, "querying SAD entry with SPI %.8x for update", |
1909 | ntohl(id->spi)); | |
7daf5226 | 1910 | |
1adaa02b TB |
1911 | msg = (struct sadb_msg*)request; |
1912 | msg->sadb_msg_version = PF_KEY_V2; | |
1913 | msg->sadb_msg_type = SADB_GET; | |
89da06ac | 1914 | msg->sadb_msg_satype = proto2satype(id->proto); |
1adaa02b | 1915 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); |
7daf5226 | 1916 | |
1adaa02b TB |
1917 | sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); |
1918 | sa->sadb_sa_exttype = SADB_EXT_SA; | |
1919 | sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); | |
89da06ac | 1920 | sa->sadb_sa_spi = id->spi; |
4ae2209e | 1921 | sa->sadb_sa_state = SADB_SASTATE_MATURE; |
1adaa02b | 1922 | PFKEY_EXT_ADD(msg, sa); |
7daf5226 | 1923 | |
bf08e394 | 1924 | add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); |
89da06ac | 1925 | add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); |
7daf5226 | 1926 | |
1adaa02b TB |
1927 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) |
1928 | { | |
89da06ac TB |
1929 | DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", |
1930 | ntohl(id->spi)); | |
1adaa02b TB |
1931 | return FAILED; |
1932 | } | |
1933 | else if (out->sadb_msg_errno) | |
1934 | { | |
1935 | DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)", | |
89da06ac TB |
1936 | ntohl(id->spi), strerror(out->sadb_msg_errno), |
1937 | out->sadb_msg_errno); | |
1adaa02b TB |
1938 | free(out); |
1939 | return FAILED; | |
1940 | } | |
1941 | else if (parse_pfkey_message(out, &response) != SUCCESS) | |
1942 | { | |
108357b1 | 1943 | DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: parsing " |
89da06ac | 1944 | "response from kernel failed", ntohl(id->spi)); |
1adaa02b TB |
1945 | free(out); |
1946 | return FAILED; | |
1947 | } | |
7daf5226 | 1948 | |
1adaa02b | 1949 | DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", |
89da06ac | 1950 | ntohl(id->spi), id->src, id->dst, data->new_src, data->new_dst); |
7daf5226 | 1951 | |
1adaa02b | 1952 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1953 | |
1adaa02b TB |
1954 | msg = (struct sadb_msg*)request; |
1955 | msg->sadb_msg_version = PF_KEY_V2; | |
ea625fab | 1956 | msg->sadb_msg_type = SADB_UPDATE; |
89da06ac | 1957 | msg->sadb_msg_satype = proto2satype(id->proto); |
1adaa02b | 1958 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); |
7daf5226 | 1959 | |
e20bd8b6 TB |
1960 | #ifdef __APPLE__ |
1961 | { | |
1962 | struct sadb_sa_2 *sa_2; | |
1963 | sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg); | |
1964 | sa_2->sa.sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa_2)); | |
1965 | memcpy(&sa_2->sa, response.sa, sizeof(struct sadb_sa)); | |
a080cfec | 1966 | if (data->new_encap) |
e20bd8b6 | 1967 | { |
89da06ac | 1968 | sa_2->sadb_sa_natt_port = data->new_dst->get_port(data->new_dst); |
e20bd8b6 TB |
1969 | sa_2->sa.sadb_sa_flags |= SADB_X_EXT_NATT; |
1970 | } | |
1971 | } | |
1972 | #else | |
1adaa02b | 1973 | PFKEY_EXT_COPY(msg, response.sa); |
e20bd8b6 | 1974 | #endif |
1adaa02b | 1975 | PFKEY_EXT_COPY(msg, response.x_sa2); |
7daf5226 | 1976 | |
ea625fab TB |
1977 | PFKEY_EXT_COPY(msg, response.src); |
1978 | PFKEY_EXT_COPY(msg, response.dst); | |
7daf5226 | 1979 | |
1adaa02b TB |
1980 | PFKEY_EXT_COPY(msg, response.lft_soft); |
1981 | PFKEY_EXT_COPY(msg, response.lft_hard); | |
7daf5226 | 1982 | |
21a500a0 TB |
1983 | #ifndef __FreeBSD__ |
1984 | /* FreeBSD 11.1 does not allow key updates via SADB_UPDATE for mature SAs */ | |
1adaa02b TB |
1985 | if (response.key_encr) |
1986 | { | |
1987 | PFKEY_EXT_COPY(msg, response.key_encr); | |
1988 | } | |
7daf5226 | 1989 | |
1adaa02b TB |
1990 | if (response.key_auth) |
1991 | { | |
1992 | PFKEY_EXT_COPY(msg, response.key_auth); | |
1993 | } | |
21a500a0 | 1994 | #endif |
7daf5226 | 1995 | |
d24a74c5 | 1996 | #ifdef HAVE_NATT |
89da06ac | 1997 | if (data->new_encap) |
1adaa02b | 1998 | { |
89da06ac | 1999 | add_encap_ext(msg, data->new_src, data->new_dst); |
1adaa02b | 2000 | } |
d24a74c5 | 2001 | #endif /*HAVE_NATT*/ |
7daf5226 | 2002 | |
bf08e394 TB |
2003 | #ifdef SADB_X_EXT_NEW_ADDRESS_SRC |
2004 | if (!id->src->ip_equals(id->src, data->new_src)) | |
2005 | { | |
2006 | add_addr_ext(msg, data->new_src, SADB_X_EXT_NEW_ADDRESS_SRC, 0, 0, | |
2007 | FALSE); | |
2008 | } | |
2009 | if (!id->dst->ip_equals(id->dst, data->new_dst)) | |
2010 | { | |
2011 | add_addr_ext(msg, data->new_dst, SADB_X_EXT_NEW_ADDRESS_DST, 0, 0, | |
2012 | FALSE); | |
2013 | } | |
2014 | #endif /*SADB_X_EXT_NEW_ADDRESS_SRC*/ | |
2015 | ||
1adaa02b | 2016 | free(out); |
7daf5226 | 2017 | |
1adaa02b TB |
2018 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) |
2019 | { | |
89da06ac TB |
2020 | DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", |
2021 | ntohl(id->spi)); | |
1adaa02b TB |
2022 | return FAILED; |
2023 | } | |
2024 | else if (out->sadb_msg_errno) | |
2025 | { | |
2026 | DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: %s (%d)", | |
89da06ac | 2027 | ntohl(id->spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno); |
1adaa02b TB |
2028 | free(out); |
2029 | return FAILED; | |
2030 | } | |
2031 | free(out); | |
7daf5226 | 2032 | |
1adaa02b TB |
2033 | return SUCCESS; |
2034 | } | |
2035 | ||
44791b75 | 2036 | METHOD(kernel_ipsec_t, query_sa, status_t, |
89da06ac TB |
2037 | private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id, |
2038 | kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets, | |
2039 | time_t *time) | |
2ad51539 | 2040 | { |
f35f229f AS |
2041 | unsigned char request[PFKEY_BUFFER_SIZE]; |
2042 | struct sadb_msg *msg, *out; | |
2043 | struct sadb_sa *sa; | |
2044 | pfkey_msg_t response; | |
2045 | size_t len; | |
7daf5226 | 2046 | |
f35f229f | 2047 | memset(&request, 0, sizeof(request)); |
7daf5226 | 2048 | |
89da06ac | 2049 | DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(id->spi)); |
7daf5226 | 2050 | |
f35f229f AS |
2051 | msg = (struct sadb_msg*)request; |
2052 | msg->sadb_msg_version = PF_KEY_V2; | |
2053 | msg->sadb_msg_type = SADB_GET; | |
89da06ac | 2054 | msg->sadb_msg_satype = proto2satype(id->proto); |
f35f229f | 2055 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); |
7daf5226 | 2056 | |
f35f229f AS |
2057 | sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); |
2058 | sa->sadb_sa_exttype = SADB_EXT_SA; | |
2059 | sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); | |
89da06ac | 2060 | sa->sadb_sa_spi = id->spi; |
f35f229f | 2061 | PFKEY_EXT_ADD(msg, sa); |
7daf5226 | 2062 | |
f35f229f AS |
2063 | /* the Linux Kernel doesn't care for the src address, but other systems do |
2064 | * (e.g. FreeBSD) | |
2065 | */ | |
89da06ac TB |
2066 | add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); |
2067 | add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); | |
7daf5226 | 2068 | |
f35f229f AS |
2069 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) |
2070 | { | |
89da06ac TB |
2071 | DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", |
2072 | ntohl(id->spi)); | |
f35f229f AS |
2073 | return FAILED; |
2074 | } | |
2075 | else if (out->sadb_msg_errno) | |
2076 | { | |
2077 | DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)", | |
89da06ac TB |
2078 | ntohl(id->spi), strerror(out->sadb_msg_errno), |
2079 | out->sadb_msg_errno); | |
f35f229f AS |
2080 | free(out); |
2081 | return FAILED; | |
2082 | } | |
2083 | else if (parse_pfkey_message(out, &response) != SUCCESS) | |
2084 | { | |
89da06ac TB |
2085 | DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", |
2086 | ntohl(id->spi)); | |
f35f229f AS |
2087 | free(out); |
2088 | return FAILED; | |
2089 | } | |
7eeeb1c7 MW |
2090 | if (bytes) |
2091 | { | |
2092 | *bytes = response.lft_current->sadb_lifetime_bytes; | |
2093 | } | |
2094 | if (packets) | |
2095 | { | |
25fcbab6 TB |
2096 | /* at least on Linux and FreeBSD this contains the number of packets */ |
2097 | *packets = response.lft_current->sadb_lifetime_allocations; | |
7eeeb1c7 | 2098 | } |
5c12700f MW |
2099 | if (time) |
2100 | { | |
2101 | #ifdef __APPLE__ | |
2102 | /* OS X uses the "last" time of use in usetime */ | |
2103 | *time = response.lft_current->sadb_lifetime_usetime; | |
2104 | #else /* !__APPLE__ */ | |
2105 | /* on Linux, sadb_lifetime_usetime is set to the "first" time of use, | |
2106 | * which is actually correct according to PF_KEY. We have to query | |
2107 | * policies for the last usetime. */ | |
2108 | *time = 0; | |
2109 | #endif /* !__APPLE__ */ | |
2110 | } | |
f35f229f AS |
2111 | |
2112 | free(out); | |
2113 | return SUCCESS; | |
2ad51539 AS |
2114 | } |
2115 | ||
44791b75 | 2116 | METHOD(kernel_ipsec_t, del_sa, status_t, |
89da06ac TB |
2117 | private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id, |
2118 | kernel_ipsec_del_sa_t *data) | |
1adaa02b TB |
2119 | { |
2120 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
2121 | struct sadb_msg *msg, *out; | |
2122 | struct sadb_sa *sa; | |
1adaa02b | 2123 | size_t len; |
7daf5226 | 2124 | |
6afa7761 | 2125 | /* if IPComp was used, we first delete the additional IPComp SA */ |
89da06ac | 2126 | if (data->cpi) |
6afa7761 | 2127 | { |
89da06ac TB |
2128 | kernel_ipsec_sa_id_t ipcomp_id = { |
2129 | .src = id->src, | |
2130 | .dst = id->dst, | |
2131 | .spi = htonl(ntohs(data->cpi)), | |
2132 | .proto = IPPROTO_COMP, | |
2133 | .mark = id->mark, | |
2134 | }; | |
2135 | kernel_ipsec_del_sa_t ipcomp = { 0 }; | |
2136 | del_sa(this, &ipcomp_id, &ipcomp); | |
6afa7761 FK |
2137 | } |
2138 | ||
1adaa02b | 2139 | memset(&request, 0, sizeof(request)); |
7daf5226 | 2140 | |
89da06ac | 2141 | DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(id->spi)); |
7daf5226 | 2142 | |
1adaa02b TB |
2143 | msg = (struct sadb_msg*)request; |
2144 | msg->sadb_msg_version = PF_KEY_V2; | |
2145 | msg->sadb_msg_type = SADB_DELETE; | |
89da06ac | 2146 | msg->sadb_msg_satype = proto2satype(id->proto); |
1adaa02b | 2147 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); |
7daf5226 | 2148 | |
1adaa02b TB |
2149 | sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg); |
2150 | sa->sadb_sa_exttype = SADB_EXT_SA; | |
2151 | sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); | |
89da06ac | 2152 | sa->sadb_sa_spi = id->spi; |
1adaa02b | 2153 | PFKEY_EXT_ADD(msg, sa); |
7daf5226 | 2154 | |
f35f229f AS |
2155 | /* the Linux Kernel doesn't care for the src address, but other systems do |
2156 | * (e.g. FreeBSD) | |
2157 | */ | |
89da06ac TB |
2158 | add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); |
2159 | add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); | |
7daf5226 | 2160 | |
1adaa02b TB |
2161 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) |
2162 | { | |
89da06ac TB |
2163 | DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", |
2164 | ntohl(id->spi)); | |
1adaa02b TB |
2165 | return FAILED; |
2166 | } | |
2167 | else if (out->sadb_msg_errno) | |
2168 | { | |
2169 | DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x: %s (%d)", | |
89da06ac TB |
2170 | ntohl(id->spi), strerror(out->sadb_msg_errno), |
2171 | out->sadb_msg_errno); | |
1adaa02b TB |
2172 | free(out); |
2173 | return FAILED; | |
2174 | } | |
7daf5226 | 2175 | |
89da06ac | 2176 | DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(id->spi)); |
1adaa02b TB |
2177 | free(out); |
2178 | return SUCCESS; | |
2179 | } | |
2180 | ||
773572f9 TB |
2181 | METHOD(kernel_ipsec_t, flush_sas, status_t, |
2182 | private_kernel_pfkey_ipsec_t *this) | |
2183 | { | |
2184 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
2185 | struct sadb_msg *msg, *out; | |
603e3b48 | 2186 | struct { |
b12c53ce | 2187 | uint8_t proto; |
603e3b48 TB |
2188 | char *name; |
2189 | } protos[] = { | |
2190 | { SADB_SATYPE_AH, "AH" }, | |
2191 | { SADB_SATYPE_ESP, "ESP" }, | |
2192 | { SADB_X_SATYPE_IPCOMP, "IPComp" }, | |
2193 | }; | |
773572f9 | 2194 | size_t len; |
603e3b48 | 2195 | int i; |
773572f9 TB |
2196 | |
2197 | memset(&request, 0, sizeof(request)); | |
2198 | ||
773572f9 TB |
2199 | msg = (struct sadb_msg*)request; |
2200 | msg->sadb_msg_version = PF_KEY_V2; | |
2201 | msg->sadb_msg_type = SADB_FLUSH; | |
773572f9 TB |
2202 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); |
2203 | ||
603e3b48 | 2204 | for (i = 0; i < countof(protos); i++) |
773572f9 | 2205 | { |
603e3b48 TB |
2206 | DBG2(DBG_KNL, "flushing all %s SAD entries", protos[i].name); |
2207 | ||
2208 | msg->sadb_msg_satype = protos[i].proto; | |
2209 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) | |
2210 | { | |
2211 | DBG1(DBG_KNL, "unable to flush %s SAD entries", protos[i].name); | |
2212 | return FAILED; | |
2213 | } | |
2214 | else if (out->sadb_msg_errno) | |
2215 | { | |
2216 | DBG1(DBG_KNL, "unable to flush %s SAD entries: %s (%d)", | |
2217 | protos[i].name, strerror(out->sadb_msg_errno), | |
2218 | out->sadb_msg_errno); | |
2219 | free(out); | |
2220 | return FAILED; | |
2221 | } | |
773572f9 | 2222 | free(out); |
773572f9 | 2223 | } |
773572f9 TB |
2224 | return SUCCESS; |
2225 | } | |
2226 | ||
df919d50 MW |
2227 | /** |
2228 | * Add an explicit exclude route to a routing entry | |
2229 | */ | |
2230 | static void add_exclude_route(private_kernel_pfkey_ipsec_t *this, | |
2231 | route_entry_t *route, host_t *src, host_t *dst) | |
2232 | { | |
2233 | enumerator_t *enumerator; | |
2234 | exclude_route_t *exclude; | |
2235 | host_t *gtw; | |
2236 | ||
2237 | enumerator = this->excludes->create_enumerator(this->excludes); | |
2238 | while (enumerator->enumerate(enumerator, &exclude)) | |
2239 | { | |
2240 | if (dst->ip_equals(dst, exclude->dst)) | |
2241 | { | |
2242 | route->exclude = exclude; | |
2243 | exclude->refs++; | |
2244 | } | |
2245 | } | |
2246 | enumerator->destroy(enumerator); | |
2247 | ||
2248 | if (!route->exclude) | |
2249 | { | |
2250 | DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src); | |
99a57aa5 | 2251 | gtw = charon->kernel->get_nexthop(charon->kernel, dst, -1, NULL, NULL); |
df919d50 MW |
2252 | if (gtw) |
2253 | { | |
8afd0f05 TB |
2254 | char *if_name = NULL; |
2255 | ||
8394ea2a TB |
2256 | if (charon->kernel->get_interface(charon->kernel, src, &if_name) && |
2257 | charon->kernel->add_route(charon->kernel, | |
df919d50 MW |
2258 | dst->get_address(dst), |
2259 | dst->get_family(dst) == AF_INET ? 32 : 128, | |
8afd0f05 | 2260 | gtw, src, if_name) == SUCCESS) |
df919d50 MW |
2261 | { |
2262 | INIT(exclude, | |
2263 | .dst = dst->clone(dst), | |
2264 | .src = src->clone(src), | |
2265 | .gtw = gtw->clone(gtw), | |
2266 | .refs = 1, | |
2267 | ); | |
2268 | route->exclude = exclude; | |
2269 | this->excludes->insert_last(this->excludes, exclude); | |
2270 | } | |
2271 | else | |
2272 | { | |
2273 | DBG1(DBG_KNL, "installing exclude route for %H failed", dst); | |
2274 | } | |
2275 | gtw->destroy(gtw); | |
8afd0f05 | 2276 | free(if_name); |
df919d50 MW |
2277 | } |
2278 | else | |
2279 | { | |
2280 | DBG1(DBG_KNL, "gateway lookup for for %H failed", dst); | |
2281 | } | |
2282 | } | |
2283 | } | |
2284 | ||
2285 | /** | |
2286 | * Remove an exclude route attached to a routing entry | |
2287 | */ | |
2288 | static void remove_exclude_route(private_kernel_pfkey_ipsec_t *this, | |
2289 | route_entry_t *route) | |
2290 | { | |
2291 | if (route->exclude) | |
2292 | { | |
2293 | enumerator_t *enumerator; | |
2294 | exclude_route_t *exclude; | |
2295 | bool removed = FALSE; | |
2296 | host_t *dst; | |
2297 | ||
2298 | enumerator = this->excludes->create_enumerator(this->excludes); | |
2299 | while (enumerator->enumerate(enumerator, &exclude)) | |
2300 | { | |
2301 | if (route->exclude == exclude) | |
2302 | { | |
2303 | if (--exclude->refs == 0) | |
2304 | { | |
2305 | this->excludes->remove_at(this->excludes, enumerator); | |
2306 | removed = TRUE; | |
2307 | break; | |
2308 | } | |
2309 | } | |
2310 | } | |
2311 | enumerator->destroy(enumerator); | |
2312 | ||
2313 | if (removed) | |
2314 | { | |
8afd0f05 TB |
2315 | char *if_name = NULL; |
2316 | ||
df919d50 MW |
2317 | dst = route->exclude->dst; |
2318 | DBG2(DBG_KNL, "uninstalling exclude route for %H src %H", | |
2319 | dst, route->exclude->src); | |
8394ea2a TB |
2320 | if (charon->kernel->get_interface( |
2321 | charon->kernel, | |
8afd0f05 | 2322 | route->exclude->src, &if_name) && |
8394ea2a | 2323 | charon->kernel->del_route(charon->kernel, |
df919d50 MW |
2324 | dst->get_address(dst), |
2325 | dst->get_family(dst) == AF_INET ? 32 : 128, | |
2326 | route->exclude->gtw, route->exclude->src, | |
8afd0f05 | 2327 | if_name) != SUCCESS) |
df919d50 MW |
2328 | { |
2329 | DBG1(DBG_KNL, "uninstalling exclude route for %H failed", dst); | |
2330 | } | |
2331 | exclude_route_destroy(route->exclude); | |
8afd0f05 | 2332 | free(if_name); |
df919d50 MW |
2333 | } |
2334 | route->exclude = NULL; | |
2335 | } | |
2336 | } | |
2337 | ||
5f7f8c92 | 2338 | /** |
b98afc0a | 2339 | * Try to install a route to the given outbound policy |
5f7f8c92 MW |
2340 | */ |
2341 | static bool install_route(private_kernel_pfkey_ipsec_t *this, | |
b98afc0a | 2342 | policy_entry_t *policy, policy_sa_out_t *out) |
5f7f8c92 MW |
2343 | { |
2344 | route_entry_t *route, *old; | |
2345 | host_t *host, *src, *dst; | |
ca4a14ae | 2346 | bool is_virtual; |
5f7f8c92 | 2347 | |
b98afc0a | 2348 | if (charon->kernel->get_address_by_ts(charon->kernel, out->src_ts, &host, |
8394ea2a | 2349 | &is_virtual) != SUCCESS) |
5f7f8c92 MW |
2350 | { |
2351 | return FALSE; | |
2352 | } | |
2353 | ||
5f7f8c92 | 2354 | INIT(route, |
b98afc0a | 2355 | .prefixlen = policy->dst.mask, |
5f7f8c92 | 2356 | .src_ip = host, |
b98afc0a | 2357 | .dst_net = chunk_clone(policy->dst.net->get_address(policy->dst.net)), |
5f7f8c92 MW |
2358 | ); |
2359 | ||
b98afc0a TB |
2360 | src = out->generic.sa->src; |
2361 | dst = out->generic.sa->dst; | |
2362 | ||
60f5fb23 TB |
2363 | if (!dst->is_anyaddr(dst)) |
2364 | { | |
8394ea2a | 2365 | route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1, |
50798628 | 2366 | src, &route->if_name); |
f22add05 TB |
2367 | |
2368 | /* if the IP is virtual, we install the route over the interface it has | |
2369 | * been installed on. Otherwise we use the interface we use for IKE, as | |
2370 | * this is required for example on Linux. */ | |
e8116593 | 2371 | if (is_virtual || this->route_via_internal) |
f22add05 | 2372 | { |
50798628 TB |
2373 | free(route->if_name); |
2374 | route->if_name = NULL; | |
f22add05 TB |
2375 | src = route->src_ip; |
2376 | } | |
60f5fb23 TB |
2377 | } |
2378 | else | |
2379 | { /* for shunt policies */ | |
8394ea2a | 2380 | route->gateway = charon->kernel->get_nexthop(charon->kernel, |
b98afc0a | 2381 | policy->dst.net, policy->dst.mask, |
c158331b | 2382 | route->src_ip, &route->if_name); |
60f5fb23 | 2383 | |
f22add05 | 2384 | /* we don't have a source address, use the address we found */ |
ca4a14ae MW |
2385 | src = route->src_ip; |
2386 | } | |
2387 | ||
5f7f8c92 | 2388 | /* get interface for route, using source address */ |
c158331b TB |
2389 | if (!route->if_name && |
2390 | !charon->kernel->get_interface(charon->kernel, src, &route->if_name)) | |
5f7f8c92 MW |
2391 | { |
2392 | route_entry_destroy(route); | |
2393 | return FALSE; | |
2394 | } | |
2395 | ||
2396 | if (policy->route) | |
2397 | { | |
2398 | old = policy->route; | |
2399 | ||
2400 | if (route_entry_equals(old, route)) | |
2401 | { /* such a route already exists */ | |
2402 | route_entry_destroy(route); | |
2403 | return TRUE; | |
2404 | } | |
2405 | /* uninstall previously installed route */ | |
8394ea2a TB |
2406 | if (charon->kernel->del_route(charon->kernel, old->dst_net, |
2407 | old->prefixlen, old->gateway, | |
2408 | old->src_ip, old->if_name) != SUCCESS) | |
5f7f8c92 MW |
2409 | { |
2410 | DBG1(DBG_KNL, "error uninstalling route installed with policy " | |
b98afc0a | 2411 | "%R === %R %N", out->src_ts, out->dst_ts, |
5f7f8c92 MW |
2412 | policy_dir_names, policy->direction); |
2413 | } | |
2414 | route_entry_destroy(old); | |
2415 | policy->route = NULL; | |
2416 | } | |
2417 | ||
df919d50 | 2418 | /* if remote traffic selector covers the IKE peer, add an exclude route */ |
8394ea2a | 2419 | if (charon->kernel->get_features(charon->kernel) & KERNEL_REQUIRE_EXCLUDE_ROUTE) |
df919d50 | 2420 | { |
b98afc0a | 2421 | if (out->dst_ts->is_host(out->dst_ts, dst)) |
e5b5a667 TB |
2422 | { |
2423 | DBG1(DBG_KNL, "can't install route for %R === %R %N, conflicts " | |
b98afc0a | 2424 | "with IKE traffic", out->src_ts, out->dst_ts, policy_dir_names, |
e5b5a667 TB |
2425 | policy->direction); |
2426 | route_entry_destroy(route); | |
2427 | return FALSE; | |
2428 | } | |
b98afc0a | 2429 | if (out->dst_ts->includes(out->dst_ts, dst)) |
df919d50 | 2430 | { |
b98afc0a | 2431 | add_exclude_route(this, route, out->generic.sa->src, dst); |
df919d50 MW |
2432 | } |
2433 | } | |
2434 | ||
5f7f8c92 | 2435 | DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s", |
b98afc0a | 2436 | out->dst_ts, route->gateway, route->src_ip, route->if_name); |
5f7f8c92 | 2437 | |
8394ea2a TB |
2438 | switch (charon->kernel->add_route(charon->kernel, route->dst_net, |
2439 | route->prefixlen, route->gateway, | |
2440 | route->src_ip, route->if_name)) | |
5f7f8c92 MW |
2441 | { |
2442 | case ALREADY_DONE: | |
2443 | /* route exists, do not uninstall */ | |
df919d50 | 2444 | remove_exclude_route(this, route); |
5f7f8c92 MW |
2445 | route_entry_destroy(route); |
2446 | return TRUE; | |
2447 | case SUCCESS: | |
2448 | /* cache the installed route */ | |
2449 | policy->route = route; | |
2450 | return TRUE; | |
2451 | default: | |
2452 | DBG1(DBG_KNL, "installing route failed: %R via %H src %H dev %s", | |
b98afc0a | 2453 | out->dst_ts, route->gateway, route->src_ip, route->if_name); |
df919d50 | 2454 | remove_exclude_route(this, route); |
5f7f8c92 MW |
2455 | route_entry_destroy(route); |
2456 | return FALSE; | |
2457 | } | |
2458 | } | |
2459 | ||
50c4c1bb TB |
2460 | /** |
2461 | * Check if any significant data has changed to warrant sending an update to | |
2462 | * the kernel. | |
2463 | */ | |
2464 | static bool policy_update_required(policy_sa_t *current, policy_sa_t *updated) | |
2465 | { | |
2466 | if (current->type != updated->type | |
2467 | #ifdef HAVE_STRUCT_SADB_X_POLICY_SADB_X_POLICY_PRIORITY | |
2468 | || current->priority != updated->priority | |
2469 | #endif | |
2470 | ) | |
2471 | { | |
2472 | return TRUE; | |
2473 | } | |
2474 | if (current->type == POLICY_IPSEC) | |
2475 | { | |
2476 | ipsec_sa_cfg_t *cur = ¤t->sa->cfg, *upd = &updated->sa->cfg; | |
2477 | ||
2478 | /* we don't use ipsec_sa_cfg_equals() here as e.g. SPIs are not | |
2479 | * relevant for this kernel interface, so we don't have to update the | |
2480 | * policy during a rekeying */ | |
2481 | if (cur->mode != upd->mode || | |
2482 | cur->reqid != upd->reqid || | |
2483 | cur->esp.use != upd->esp.use || | |
2484 | cur->ah.use != upd->ah.use || | |
2485 | cur->ipcomp.transform != upd->ipcomp.transform) | |
2486 | { | |
2487 | return TRUE; | |
2488 | } | |
2489 | if (cur->mode == MODE_TUNNEL && | |
2490 | (!current->sa->src->ip_equals(current->sa->src, updated->sa->src) || | |
2491 | !current->sa->dst->ip_equals(current->sa->dst, updated->sa->dst))) | |
2492 | { | |
2493 | return TRUE; | |
2494 | } | |
2495 | } | |
2496 | return FALSE; | |
2497 | } | |
2498 | ||
17927ca6 TB |
2499 | /** |
2500 | * Add or update a policy in the kernel. | |
2501 | * | |
2502 | * Note: The mutex has to be locked when entering this function. | |
2503 | */ | |
2504 | static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, | |
2505 | policy_entry_t *policy, policy_sa_t *mapping, bool update) | |
1adaa02b TB |
2506 | { |
2507 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
2508 | struct sadb_msg *msg, *out; | |
2509 | struct sadb_x_policy *pol; | |
1adaa02b | 2510 | struct sadb_x_ipsecrequest *req; |
17927ca6 | 2511 | ipsec_sa_t *ipsec = mapping->sa; |
1adaa02b TB |
2512 | pfkey_msg_t response; |
2513 | size_t len; | |
6afa7761 | 2514 | ipsec_mode_t proto_mode; |
695112d7 | 2515 | status_t status; |
7daf5226 | 2516 | |
1adaa02b | 2517 | memset(&request, 0, sizeof(request)); |
7daf5226 | 2518 | |
1adaa02b TB |
2519 | msg = (struct sadb_msg*)request; |
2520 | msg->sadb_msg_version = PF_KEY_V2; | |
17927ca6 | 2521 | msg->sadb_msg_type = update ? SADB_X_SPDUPDATE : SADB_X_SPDADD; |
1adaa02b TB |
2522 | msg->sadb_msg_satype = 0; |
2523 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); | |
7daf5226 | 2524 | |
1adaa02b TB |
2525 | pol = (struct sadb_x_policy*)PFKEY_EXT_ADD_NEXT(msg); |
2526 | pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; | |
2527 | pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy)); | |
2528 | pol->sadb_x_policy_id = 0; | |
17927ca6 TB |
2529 | pol->sadb_x_policy_dir = dir2kernel(policy->direction); |
2530 | pol->sadb_x_policy_type = type2kernel(mapping->type); | |
d24a74c5 | 2531 | #ifdef HAVE_STRUCT_SADB_X_POLICY_SADB_X_POLICY_PRIORITY |
17927ca6 | 2532 | pol->sadb_x_policy_priority = mapping->priority; |
d24a74c5 | 2533 | #endif |
7daf5226 | 2534 | |
0ff8ce94 TB |
2535 | if (mapping->type == POLICY_IPSEC && ipsec->cfg.reqid) |
2536 | { | |
2537 | /* one or more sadb_x_ipsecrequest extensions are added to the | |
2538 | * sadb_x_policy extension */ | |
2539 | proto_mode = ipsec->cfg.mode; | |
6afa7761 | 2540 | |
0ff8ce94 | 2541 | req = (struct sadb_x_ipsecrequest*)(pol + 1); |
6afa7761 | 2542 | |
0ff8ce94 TB |
2543 | if (ipsec->cfg.ipcomp.transform != IPCOMP_NONE) |
2544 | { | |
2545 | req->sadb_x_ipsecrequest_proto = IPPROTO_COMP; | |
2546 | ||
2547 | /* !!! the length here MUST be in octets instead of 64 bit words */ | |
2548 | req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest); | |
2549 | req->sadb_x_ipsecrequest_mode = mode2kernel(ipsec->cfg.mode); | |
2550 | req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid; | |
2551 | req->sadb_x_ipsecrequest_level = (policy->direction == POLICY_OUT) ? | |
2552 | IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_USE; | |
2553 | if (ipsec->cfg.mode == MODE_TUNNEL) | |
2554 | { | |
2555 | len = hostcpy(req + 1, ipsec->src, FALSE); | |
2556 | req->sadb_x_ipsecrequest_len += len; | |
2557 | len = hostcpy((char*)(req + 1) + len, ipsec->dst, FALSE); | |
2558 | req->sadb_x_ipsecrequest_len += len; | |
2559 | /* use transport mode for other SAs */ | |
2560 | proto_mode = MODE_TRANSPORT; | |
2561 | } | |
6afa7761 | 2562 | |
0ff8ce94 TB |
2563 | pol->sadb_x_policy_len += PFKEY_LEN(req->sadb_x_ipsecrequest_len); |
2564 | req = (struct sadb_x_ipsecrequest*)((char*)(req) + | |
2565 | req->sadb_x_ipsecrequest_len); | |
2566 | } | |
2567 | ||
2568 | req->sadb_x_ipsecrequest_proto = ipsec->cfg.esp.use ? IPPROTO_ESP | |
2569 | : IPPROTO_AH; | |
6afa7761 FK |
2570 | /* !!! the length here MUST be in octets instead of 64 bit words */ |
2571 | req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest); | |
0ff8ce94 | 2572 | req->sadb_x_ipsecrequest_mode = mode2kernel(proto_mode); |
6afa7761 | 2573 | req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid; |
0ff8ce94 TB |
2574 | req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; |
2575 | if (proto_mode == MODE_TUNNEL) | |
6afa7761 FK |
2576 | { |
2577 | len = hostcpy(req + 1, ipsec->src, FALSE); | |
2578 | req->sadb_x_ipsecrequest_len += len; | |
2579 | len = hostcpy((char*)(req + 1) + len, ipsec->dst, FALSE); | |
2580 | req->sadb_x_ipsecrequest_len += len; | |
6afa7761 FK |
2581 | } |
2582 | ||
2583 | pol->sadb_x_policy_len += PFKEY_LEN(req->sadb_x_ipsecrequest_len); | |
6afa7761 | 2584 | } |
1adaa02b | 2585 | PFKEY_EXT_ADD(msg, pol); |
7daf5226 | 2586 | |
f55a7a76 | 2587 | add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto, |
9041c074 | 2588 | policy->src.mask, TRUE); |
f55a7a76 | 2589 | add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto, |
9041c074 | 2590 | policy->dst.mask, TRUE); |
7daf5226 | 2591 | |
bfca7aa5 TB |
2592 | #ifdef __FreeBSD__ |
2593 | { /* on FreeBSD a lifetime has to be defined to be able to later query | |
2594 | * the current use time. */ | |
2595 | struct sadb_lifetime *lft; | |
2596 | lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); | |
2597 | lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; | |
2598 | lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime)); | |
79ff6141 | 2599 | lft->sadb_lifetime_addtime = LONG_MAX; |
bfca7aa5 TB |
2600 | PFKEY_EXT_ADD(msg, lft); |
2601 | } | |
2602 | #endif | |
7daf5226 | 2603 | |
3ac5a0db | 2604 | this->mutex->unlock(this->mutex); |
7daf5226 | 2605 | |
695112d7 TB |
2606 | status = pfkey_send(this, msg, &out, &len); |
2607 | if (status == SUCCESS && !update && out->sadb_msg_errno == EEXIST) | |
2608 | { | |
2609 | DBG1(DBG_KNL, "policy already exists, try to update it"); | |
2610 | free(out); | |
2611 | msg->sadb_msg_type = SADB_X_SPDUPDATE; | |
2612 | status = pfkey_send(this, msg, &out, &len); | |
2613 | } | |
2614 | if (status != SUCCESS) | |
1adaa02b | 2615 | { |
1adaa02b TB |
2616 | return FAILED; |
2617 | } | |
2618 | else if (out->sadb_msg_errno) | |
2619 | { | |
17927ca6 TB |
2620 | DBG1(DBG_KNL, "unable to %s policy: %s (%d)", |
2621 | update ? "update" : "add", strerror(out->sadb_msg_errno), | |
2622 | out->sadb_msg_errno); | |
1adaa02b TB |
2623 | free(out); |
2624 | return FAILED; | |
2625 | } | |
2626 | else if (parse_pfkey_message(out, &response) != SUCCESS) | |
2627 | { | |
17927ca6 TB |
2628 | DBG1(DBG_KNL, "unable to %s policy: parsing response from kernel " |
2629 | "failed", update ? "update" : "add"); | |
1adaa02b TB |
2630 | free(out); |
2631 | return FAILED; | |
2632 | } | |
7daf5226 | 2633 | |
1adaa02b | 2634 | /* we try to find the policy again and update the kernel index */ |
108357b1 | 2635 | this->mutex->lock(this->mutex); |
2e4d110d | 2636 | if (!this->policies->find_first(this->policies, NULL, (void**)&policy)) |
1adaa02b | 2637 | { |
17927ca6 TB |
2638 | DBG2(DBG_KNL, "unable to update index, the policy is already gone, " |
2639 | "ignoring"); | |
3ac5a0db | 2640 | this->mutex->unlock(this->mutex); |
1adaa02b TB |
2641 | free(out); |
2642 | return SUCCESS; | |
2643 | } | |
2644 | policy->index = response.x_policy->sadb_x_policy_id; | |
2645 | free(out); | |
7daf5226 | 2646 | |
1adaa02b | 2647 | /* install a route, if: |
b98afc0a | 2648 | * - this is an outbound policy (to just get one for each child) |
1adaa02b | 2649 | * - routing is not disabled via strongswan.conf |
85fed13c TB |
2650 | * - the selector is not for a specific protocol/port |
2651 | * - we are in tunnel mode or install a bypass policy | |
1adaa02b | 2652 | */ |
b98afc0a | 2653 | if (policy->direction == POLICY_OUT && this->install_routes && |
85fed13c TB |
2654 | policy->src.proto == IPSEC_PROTO_ANY && |
2655 | !policy->src.net->get_port(policy->src.net) && | |
2656 | !policy->dst.net->get_port(policy->dst.net)) | |
1adaa02b | 2657 | { |
85fed13c TB |
2658 | if (mapping->type == POLICY_PASS || |
2659 | (mapping->type == POLICY_IPSEC && ipsec->cfg.mode != MODE_TRANSPORT)) | |
2660 | { | |
b98afc0a | 2661 | install_route(this, policy, (policy_sa_out_t*)mapping); |
85fed13c | 2662 | } |
d24a74c5 | 2663 | } |
d24a74c5 | 2664 | this->mutex->unlock(this->mutex); |
1adaa02b TB |
2665 | return SUCCESS; |
2666 | } | |
2667 | ||
17927ca6 | 2668 | METHOD(kernel_ipsec_t, add_policy, status_t, |
89da06ac TB |
2669 | private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id, |
2670 | kernel_ipsec_manage_policy_t *data) | |
17927ca6 TB |
2671 | { |
2672 | policy_entry_t *policy, *found = NULL; | |
50c4c1bb | 2673 | policy_sa_t *assigned_sa, *current_sa = NULL; |
17927ca6 TB |
2674 | enumerator_t *enumerator; |
2675 | bool update = TRUE; | |
2676 | ||
89da06ac | 2677 | if (dir2kernel(id->dir) == IPSEC_DIR_INVALID) |
17927ca6 TB |
2678 | { /* FWD policies are not supported on all platforms */ |
2679 | return SUCCESS; | |
2680 | } | |
2681 | ||
2682 | /* create a policy */ | |
89da06ac | 2683 | policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); |
17927ca6 TB |
2684 | |
2685 | /* find a matching policy */ | |
2686 | this->mutex->lock(this->mutex); | |
2e4d110d TB |
2687 | if (this->policies->find_first(this->policies, policy_entry_equals, |
2688 | (void**)&found, policy)) | |
17927ca6 TB |
2689 | { /* use existing policy */ |
2690 | DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " | |
89da06ac | 2691 | "refcount", id->src_ts, id->dst_ts, policy_dir_names, id->dir); |
17927ca6 TB |
2692 | policy_entry_destroy(policy, this); |
2693 | policy = found; | |
2694 | } | |
2695 | else | |
2696 | { /* use the new one, if we have no such policy */ | |
0f3ddbd1 | 2697 | this->policies->insert_first(this->policies, policy); |
17927ca6 TB |
2698 | policy->used_by = linked_list_create(); |
2699 | } | |
2700 | ||
2701 | /* cache the assigned IPsec SA */ | |
89da06ac TB |
2702 | assigned_sa = policy_sa_create(this, id->dir, data->type, data->src, |
2703 | data->dst, id->src_ts, id->dst_ts, data->sa); | |
254726b5 TB |
2704 | assigned_sa->auto_priority = get_priority(policy, data->prio); |
2705 | assigned_sa->priority = data->manual_prio ? data->manual_prio : | |
2706 | assigned_sa->auto_priority; | |
2707 | ||
17927ca6 TB |
2708 | |
2709 | /* insert the SA according to its priority */ | |
2710 | enumerator = policy->used_by->create_enumerator(policy->used_by); | |
2711 | while (enumerator->enumerate(enumerator, (void**)¤t_sa)) | |
2712 | { | |
fd8f1194 TB |
2713 | if (current_sa->priority > assigned_sa->priority) |
2714 | { | |
2715 | break; | |
2716 | } | |
254726b5 | 2717 | if (current_sa->priority == assigned_sa->priority) |
17927ca6 | 2718 | { |
254726b5 TB |
2719 | /* in case of equal manual prios order SAs by automatic priority */ |
2720 | if (current_sa->auto_priority > assigned_sa->auto_priority) | |
2721 | { | |
2722 | break; | |
2723 | } | |
2724 | /* prefer SAs with a reqid over those without */ | |
2725 | if (current_sa->auto_priority == assigned_sa->auto_priority && | |
2726 | (!current_sa->sa->cfg.reqid || assigned_sa->sa->cfg.reqid)) | |
2727 | { | |
2728 | break; | |
2729 | } | |
17927ca6 TB |
2730 | } |
2731 | update = FALSE; | |
2732 | } | |
2733 | policy->used_by->insert_before(policy->used_by, enumerator, assigned_sa); | |
2734 | enumerator->destroy(enumerator); | |
2735 | ||
50c4c1bb TB |
2736 | if (update && current_sa) |
2737 | { /* check if there are actually any relevant changes, if not, we don't | |
2738 | * send an update to the kernel as e.g. FreeBSD doesn't do that | |
2739 | * atomically, causing unecessary traffic loss during rekeyings */ | |
2740 | update = policy_update_required(current_sa, assigned_sa); | |
2741 | } | |
2742 | ||
17927ca6 TB |
2743 | if (!update) |
2744 | { /* we don't update the policy if the priority is lower than that of the | |
2745 | * currently installed one */ | |
2746 | this->mutex->unlock(this->mutex); | |
2747 | return SUCCESS; | |
2748 | } | |
2749 | ||
2750 | DBG2(DBG_KNL, "%s policy %R === %R %N", | |
89da06ac TB |
2751 | found ? "updating" : "adding", id->src_ts, id->dst_ts, |
2752 | policy_dir_names, id->dir); | |
17927ca6 TB |
2753 | |
2754 | if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS) | |
2755 | { | |
2756 | DBG1(DBG_KNL, "unable to %s policy %R === %R %N", | |
89da06ac TB |
2757 | found ? "update" : "add", id->src_ts, id->dst_ts, |
2758 | policy_dir_names, id->dir); | |
17927ca6 TB |
2759 | return FAILED; |
2760 | } | |
2761 | return SUCCESS; | |
2762 | } | |
2763 | ||
44791b75 | 2764 | METHOD(kernel_ipsec_t, query_policy, status_t, |
89da06ac TB |
2765 | private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id, |
2766 | kernel_ipsec_query_policy_t *data, time_t *use_time) | |
1adaa02b TB |
2767 | { |
2768 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
2769 | struct sadb_msg *msg, *out; | |
2770 | struct sadb_x_policy *pol; | |
1adaa02b TB |
2771 | policy_entry_t *policy, *found = NULL; |
2772 | pfkey_msg_t response; | |
2773 | size_t len; | |
7daf5226 | 2774 | |
89da06ac | 2775 | if (dir2kernel(id->dir) == IPSEC_DIR_INVALID) |
108357b1 | 2776 | { /* FWD policies are not supported on all platforms */ |
eab05274 TB |
2777 | return NOT_FOUND; |
2778 | } | |
7daf5226 | 2779 | |
89da06ac TB |
2780 | DBG2(DBG_KNL, "querying policy %R === %R %N", id->src_ts, id->dst_ts, |
2781 | policy_dir_names, id->dir); | |
1adaa02b TB |
2782 | |
2783 | /* create a policy */ | |
89da06ac | 2784 | policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); |
7daf5226 | 2785 | |
1adaa02b | 2786 | /* find a matching policy */ |
3ac5a0db | 2787 | this->mutex->lock(this->mutex); |
2e4d110d TB |
2788 | if (!this->policies->find_first(this->policies, policy_entry_equals, |
2789 | (void**)&found, policy)) | |
1adaa02b | 2790 | { |
89da06ac TB |
2791 | DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found", |
2792 | id->src_ts, id->dst_ts, policy_dir_names, id->dir); | |
17927ca6 | 2793 | policy_entry_destroy(policy, this); |
3ac5a0db | 2794 | this->mutex->unlock(this->mutex); |
1adaa02b TB |
2795 | return NOT_FOUND; |
2796 | } | |
17927ca6 | 2797 | policy_entry_destroy(policy, this); |
1adaa02b | 2798 | policy = found; |
7daf5226 | 2799 | |
1adaa02b | 2800 | memset(&request, 0, sizeof(request)); |
7daf5226 | 2801 | |
1adaa02b TB |
2802 | msg = (struct sadb_msg*)request; |
2803 | msg->sadb_msg_version = PF_KEY_V2; | |
2804 | msg->sadb_msg_type = SADB_X_SPDGET; | |
2805 | msg->sadb_msg_satype = 0; | |
2806 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); | |
7daf5226 | 2807 | |
1adaa02b TB |
2808 | pol = (struct sadb_x_policy*)PFKEY_EXT_ADD_NEXT(msg); |
2809 | pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; | |
2810 | pol->sadb_x_policy_id = policy->index; | |
2811 | pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy)); | |
89da06ac | 2812 | pol->sadb_x_policy_dir = dir2kernel(id->dir); |
1adaa02b TB |
2813 | pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; |
2814 | PFKEY_EXT_ADD(msg, pol); | |
7daf5226 | 2815 | |
f55a7a76 | 2816 | add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto, |
9041c074 | 2817 | policy->src.mask, TRUE); |
f55a7a76 | 2818 | add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto, |
9041c074 | 2819 | policy->dst.mask, TRUE); |
7daf5226 | 2820 | |
3ac5a0db | 2821 | this->mutex->unlock(this->mutex); |
7daf5226 | 2822 | |
1adaa02b TB |
2823 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) |
2824 | { | |
89da06ac TB |
2825 | DBG1(DBG_KNL, "unable to query policy %R === %R %N", id->src_ts, |
2826 | id->dst_ts, policy_dir_names, id->dir); | |
1adaa02b TB |
2827 | return FAILED; |
2828 | } | |
2829 | else if (out->sadb_msg_errno) | |
2830 | { | |
89da06ac TB |
2831 | DBG1(DBG_KNL, "unable to query policy %R === %R %N: %s (%d)", |
2832 | id->src_ts, id->dst_ts, policy_dir_names, id->dir, | |
2833 | strerror(out->sadb_msg_errno), out->sadb_msg_errno); | |
1adaa02b TB |
2834 | free(out); |
2835 | return FAILED; | |
2836 | } | |
2837 | else if (parse_pfkey_message(out, &response) != SUCCESS) | |
2838 | { | |
2839 | DBG1(DBG_KNL, "unable to query policy %R === %R %N: parsing response " | |
89da06ac TB |
2840 | "from kernel failed", id->src_ts, id->dst_ts, policy_dir_names, |
2841 | id->dir); | |
1adaa02b TB |
2842 | free(out); |
2843 | return FAILED; | |
2844 | } | |
524f9ac4 TB |
2845 | else if (response.lft_current == NULL) |
2846 | { | |
5c12700f | 2847 | DBG2(DBG_KNL, "unable to query policy %R === %R %N: kernel reports no " |
89da06ac TB |
2848 | "use time", id->src_ts, id->dst_ts, policy_dir_names, |
2849 | id->dir); | |
524f9ac4 TB |
2850 | free(out); |
2851 | return FAILED; | |
2852 | } | |
108357b1 | 2853 | |
6180a558 MW |
2854 | /* we need the monotonic time, but the kernel returns system time. */ |
2855 | if (response.lft_current->sadb_lifetime_usetime) | |
2856 | { | |
2857 | *use_time = time_monotonic(NULL) - | |
2858 | (time(NULL) - response.lft_current->sadb_lifetime_usetime); | |
2859 | } | |
2860 | else | |
2861 | { | |
2862 | *use_time = 0; | |
2863 | } | |
1adaa02b | 2864 | free(out); |
1adaa02b TB |
2865 | return SUCCESS; |
2866 | } | |
2867 | ||
44791b75 | 2868 | METHOD(kernel_ipsec_t, del_policy, status_t, |
89da06ac TB |
2869 | private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id, |
2870 | kernel_ipsec_manage_policy_t *data) | |
1adaa02b TB |
2871 | { |
2872 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
2873 | struct sadb_msg *msg, *out; | |
2874 | struct sadb_x_policy *pol; | |
1adaa02b | 2875 | policy_entry_t *policy, *found = NULL; |
bbd9df25 | 2876 | policy_sa_t *mapping, *to_remove = NULL; |
17927ca6 | 2877 | enumerator_t *enumerator; |
bbd9df25 | 2878 | bool first = TRUE, is_installed = TRUE; |
254726b5 | 2879 | uint32_t priority, auto_priority; |
1adaa02b | 2880 | size_t len; |
baff14d0 | 2881 | ipsec_sa_t assigned_sa = { |
89da06ac TB |
2882 | .src = data->src, |
2883 | .dst = data->dst, | |
2884 | .cfg = *data->sa, | |
baff14d0 | 2885 | }; |
7daf5226 | 2886 | |
89da06ac | 2887 | if (dir2kernel(id->dir) == IPSEC_DIR_INVALID) |
108357b1 | 2888 | { /* FWD policies are not supported on all platforms */ |
eab05274 TB |
2889 | return SUCCESS; |
2890 | } | |
7daf5226 | 2891 | |
89da06ac TB |
2892 | DBG2(DBG_KNL, "deleting policy %R === %R %N", id->src_ts, id->dst_ts, |
2893 | policy_dir_names, id->dir); | |
7daf5226 | 2894 | |
1adaa02b | 2895 | /* create a policy */ |
89da06ac | 2896 | policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir); |
7daf5226 | 2897 | |
1adaa02b | 2898 | /* find a matching policy */ |
3ac5a0db | 2899 | this->mutex->lock(this->mutex); |
2e4d110d TB |
2900 | if (!this->policies->find_first(this->policies, policy_entry_equals, |
2901 | (void**)&found, policy)) | |
1adaa02b | 2902 | { |
89da06ac TB |
2903 | DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", |
2904 | id->src_ts, id->dst_ts, policy_dir_names, id->dir); | |
17927ca6 | 2905 | policy_entry_destroy(policy, this); |
3ac5a0db | 2906 | this->mutex->unlock(this->mutex); |
1adaa02b TB |
2907 | return NOT_FOUND; |
2908 | } | |
17927ca6 TB |
2909 | policy_entry_destroy(policy, this); |
2910 | policy = found; | |
2911 | ||
bbd9df25 TB |
2912 | /* remove mapping to SA by reqid and priority, if multiple match, which |
2913 | * could happen when rekeying due to an address change, remove the oldest */ | |
254726b5 TB |
2914 | auto_priority = get_priority(policy, data->prio); |
2915 | priority = data->manual_prio ? data->manual_prio : auto_priority; | |
17927ca6 TB |
2916 | enumerator = policy->used_by->create_enumerator(policy->used_by); |
2917 | while (enumerator->enumerate(enumerator, (void**)&mapping)) | |
2918 | { | |
baff14d0 | 2919 | if (priority == mapping->priority && |
254726b5 TB |
2920 | auto_priority == mapping->auto_priority && |
2921 | data->type == mapping->type && | |
baff14d0 | 2922 | ipsec_sa_equals(mapping->sa, &assigned_sa)) |
17927ca6 | 2923 | { |
bbd9df25 TB |
2924 | to_remove = mapping; |
2925 | is_installed = first; | |
2926 | } | |
2927 | else if (priority < mapping->priority) | |
2928 | { | |
17927ca6 TB |
2929 | break; |
2930 | } | |
bbd9df25 | 2931 | first = FALSE; |
17927ca6 TB |
2932 | } |
2933 | enumerator->destroy(enumerator); | |
e7d717cf TB |
2934 | if (!to_remove) |
2935 | { /* sanity check */ | |
2936 | this->mutex->unlock(this->mutex); | |
2937 | return SUCCESS; | |
2938 | } | |
bbd9df25 | 2939 | policy->used_by->remove(policy->used_by, to_remove, NULL); |
17927ca6 TB |
2940 | |
2941 | if (policy->used_by->get_count(policy->used_by) > 0) | |
2942 | { /* policy is used by more SAs, keep in kernel */ | |
2943 | DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); | |
50c4c1bb TB |
2944 | |
2945 | if (is_installed) | |
2946 | { /* check if there are actually any relevant changes, if not, we do | |
2947 | * not send an update to the kernel as e.g. FreeBSD doesn't do that | |
2948 | * atomically, causing unecessary traffic loss during rekeyings */ | |
2949 | policy->used_by->get_first(policy->used_by, (void**)&mapping); | |
2950 | is_installed = policy_update_required(mapping, to_remove); | |
2951 | } | |
2952 | policy_sa_destroy(to_remove, id->dir, this); | |
17927ca6 TB |
2953 | |
2954 | if (!is_installed) | |
50c4c1bb | 2955 | { /* no need to update as the policy */ |
17927ca6 TB |
2956 | this->mutex->unlock(this->mutex); |
2957 | return SUCCESS; | |
2958 | } | |
2959 | ||
89da06ac TB |
2960 | DBG2(DBG_KNL, "updating policy %R === %R %N", id->src_ts, id->dst_ts, |
2961 | policy_dir_names, id->dir); | |
17927ca6 TB |
2962 | if (add_policy_internal(this, policy, mapping, TRUE) != SUCCESS) |
2963 | { | |
2964 | DBG1(DBG_KNL, "unable to update policy %R === %R %N", | |
89da06ac | 2965 | id->src_ts, id->dst_ts, policy_dir_names, id->dir); |
17927ca6 TB |
2966 | return FAILED; |
2967 | } | |
2968 | return SUCCESS; | |
2969 | } | |
7daf5226 | 2970 | |
1adaa02b | 2971 | memset(&request, 0, sizeof(request)); |
7daf5226 | 2972 | |
1adaa02b TB |
2973 | msg = (struct sadb_msg*)request; |
2974 | msg->sadb_msg_version = PF_KEY_V2; | |
2975 | msg->sadb_msg_type = SADB_X_SPDDELETE; | |
2976 | msg->sadb_msg_satype = 0; | |
2977 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); | |
7daf5226 | 2978 | |
1adaa02b TB |
2979 | pol = (struct sadb_x_policy*)PFKEY_EXT_ADD_NEXT(msg); |
2980 | pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; | |
2981 | pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy)); | |
89da06ac | 2982 | pol->sadb_x_policy_dir = dir2kernel(id->dir); |
50c4c1bb | 2983 | pol->sadb_x_policy_type = type2kernel(to_remove->type); |
1adaa02b | 2984 | PFKEY_EXT_ADD(msg, pol); |
7daf5226 | 2985 | |
f55a7a76 | 2986 | add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto, |
9041c074 | 2987 | policy->src.mask, TRUE); |
f55a7a76 | 2988 | add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto, |
9041c074 | 2989 | policy->dst.mask, TRUE); |
7daf5226 | 2990 | |
17927ca6 TB |
2991 | if (policy->route) |
2992 | { | |
2993 | route_entry_t *route = policy->route; | |
8394ea2a TB |
2994 | if (charon->kernel->del_route(charon->kernel, route->dst_net, |
2995 | route->prefixlen, route->gateway, | |
2996 | route->src_ip, route->if_name) != SUCCESS) | |
17927ca6 TB |
2997 | { |
2998 | DBG1(DBG_KNL, "error uninstalling route installed with " | |
89da06ac TB |
2999 | "policy %R === %R %N", id->src_ts, id->dst_ts, |
3000 | policy_dir_names, id->dir); | |
17927ca6 | 3001 | } |
df919d50 | 3002 | remove_exclude_route(this, route); |
17927ca6 TB |
3003 | } |
3004 | ||
3005 | this->policies->remove(this->policies, found, NULL); | |
50c4c1bb | 3006 | policy_sa_destroy(to_remove, id->dir, this); |
17927ca6 TB |
3007 | policy_entry_destroy(policy, this); |
3008 | this->mutex->unlock(this->mutex); | |
7daf5226 | 3009 | |
1adaa02b TB |
3010 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) |
3011 | { | |
89da06ac TB |
3012 | DBG1(DBG_KNL, "unable to delete policy %R === %R %N", id->src_ts, |
3013 | id->dst_ts, policy_dir_names, id->dir); | |
1adaa02b TB |
3014 | return FAILED; |
3015 | } | |
3016 | else if (out->sadb_msg_errno) | |
3017 | { | |
89da06ac TB |
3018 | DBG1(DBG_KNL, "unable to delete policy %R === %R %N: %s (%d)", |
3019 | id->src_ts, id->dst_ts, policy_dir_names, id->dir, | |
3020 | strerror(out->sadb_msg_errno), out->sadb_msg_errno); | |
1adaa02b TB |
3021 | free(out); |
3022 | return FAILED; | |
3023 | } | |
3024 | free(out); | |
1adaa02b TB |
3025 | return SUCCESS; |
3026 | } | |
3027 | ||
773572f9 TB |
3028 | METHOD(kernel_ipsec_t, flush_policies, status_t, |
3029 | private_kernel_pfkey_ipsec_t *this) | |
3030 | { | |
3031 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
3032 | struct sadb_msg *msg, *out; | |
3033 | size_t len; | |
3034 | ||
3035 | memset(&request, 0, sizeof(request)); | |
3036 | ||
3037 | DBG2(DBG_KNL, "flushing all policies from SPD"); | |
3038 | ||
3039 | msg = (struct sadb_msg*)request; | |
3040 | msg->sadb_msg_version = PF_KEY_V2; | |
3041 | msg->sadb_msg_type = SADB_X_SPDFLUSH; | |
3042 | msg->sadb_msg_satype = SADB_SATYPE_UNSPEC; | |
3043 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); | |
3044 | ||
3045 | if (pfkey_send(this, msg, &out, &len) != SUCCESS) | |
3046 | { | |
3047 | DBG1(DBG_KNL, "unable to flush SPD entries"); | |
3048 | return FAILED; | |
3049 | } | |
3050 | else if (out->sadb_msg_errno) | |
3051 | { | |
3052 | DBG1(DBG_KNL, "unable to flush SPD entries: %s (%d)", | |
3053 | strerror(out->sadb_msg_errno), out->sadb_msg_errno); | |
3054 | free(out); | |
3055 | return FAILED; | |
3056 | } | |
3057 | free(out); | |
3058 | return SUCCESS; | |
3059 | } | |
3060 | ||
1adaa02b | 3061 | /** |
f3bb1bd0 | 3062 | * Register a socket for ACQUIRE/EXPIRE messages |
1adaa02b | 3063 | */ |
44791b75 | 3064 | static status_t register_pfkey_socket(private_kernel_pfkey_ipsec_t *this, |
b12c53ce | 3065 | uint8_t satype) |
1adaa02b TB |
3066 | { |
3067 | unsigned char request[PFKEY_BUFFER_SIZE]; | |
3068 | struct sadb_msg *msg, *out; | |
1adaa02b | 3069 | size_t len; |
7daf5226 | 3070 | |
1adaa02b | 3071 | memset(&request, 0, sizeof(request)); |
7daf5226 | 3072 | |
1adaa02b TB |
3073 | msg = (struct sadb_msg*)request; |
3074 | msg->sadb_msg_version = PF_KEY_V2; | |
3075 | msg->sadb_msg_type = SADB_REGISTER; | |
3076 | msg->sadb_msg_satype = satype; | |
3077 | msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); | |
7daf5226 | 3078 | |
1adaa02b TB |
3079 | if (pfkey_send_socket(this, this->socket_events, msg, &out, &len) != SUCCESS) |
3080 | { | |
3081 | DBG1(DBG_KNL, "unable to register PF_KEY socket"); | |
3082 | return FAILED; | |
3083 | } | |
3084 | else if (out->sadb_msg_errno) | |
3085 | { | |
3086 | DBG1(DBG_KNL, "unable to register PF_KEY socket: %s (%d)", | |
3087 | strerror(out->sadb_msg_errno), out->sadb_msg_errno); | |
3088 | free(out); | |
3089 | return FAILED; | |
3090 | } | |
3091 | free(out); | |
3092 | return SUCCESS; | |
3093 | } | |
3094 | ||
54f81859 MW |
3095 | METHOD(kernel_ipsec_t, bypass_socket, bool, |
3096 | private_kernel_pfkey_ipsec_t *this, int fd, int family) | |
ea625fab | 3097 | { |
54f81859 MW |
3098 | struct sadb_x_policy policy; |
3099 | u_int sol, ipsec_policy; | |
7daf5226 | 3100 | |
54f81859 | 3101 | switch (family) |
ea625fab | 3102 | { |
54f81859 | 3103 | case AF_INET: |
ea625fab | 3104 | { |
54f81859 MW |
3105 | sol = SOL_IP; |
3106 | ipsec_policy = IP_IPSEC_POLICY; | |
e7c27b4f | 3107 | break; |
ea625fab | 3108 | } |
54f81859 | 3109 | case AF_INET6: |
ea625fab | 3110 | { |
54f81859 MW |
3111 | sol = SOL_IPV6; |
3112 | ipsec_policy = IPV6_IPSEC_POLICY; | |
e7c27b4f | 3113 | break; |
ea625fab | 3114 | } |
54f81859 MW |
3115 | default: |
3116 | return FALSE; | |
ea625fab | 3117 | } |
54f81859 MW |
3118 | |
3119 | memset(&policy, 0, sizeof(policy)); | |
b12c53ce | 3120 | policy.sadb_x_policy_len = sizeof(policy) / sizeof(uint64_t); |
54f81859 MW |
3121 | policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; |
3122 | policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS; | |
3123 | ||
3124 | policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; | |
3125 | if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0) | |
3126 | { | |
3127 | DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s", | |
108357b1 | 3128 | strerror(errno)); |
54f81859 MW |
3129 | return FALSE; |
3130 | } | |
3131 | policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND; | |
3132 | if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0) | |
3133 | { | |
3134 | DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s", | |
108357b1 | 3135 | strerror(errno)); |
54f81859 MW |
3136 | return FALSE; |
3137 | } | |
3138 | return TRUE; | |
3139 | } | |
3140 | ||
e49abced | 3141 | METHOD(kernel_ipsec_t, enable_udp_decap, bool, |
b12c53ce | 3142 | private_kernel_pfkey_ipsec_t *this, int fd, int family, uint16_t port) |
e49abced TB |
3143 | { |
3144 | #ifndef __APPLE__ | |
3145 | int type = UDP_ENCAP_ESPINUDP; | |
3146 | ||
3147 | if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) | |
3148 | { | |
3149 | DBG1(DBG_KNL, "unable to set UDP_ENCAP: %s", strerror(errno)); | |
3150 | return FALSE; | |
3151 | } | |
3152 | #else /* __APPLE__ */ | |
889efae4 MW |
3153 | int intport = port; |
3154 | ||
3155 | if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &intport, | |
3156 | sizeof(intport)) != 0) | |
e49abced TB |
3157 | { |
3158 | DBG1(DBG_KNL, "could not set net.inet.ipsec.esp_port to %d: %s", | |
3159 | port, strerror(errno)); | |
3160 | return FALSE; | |
3161 | } | |
3162 | #endif /* __APPLE__ */ | |
3163 | ||
3164 | return TRUE; | |
3165 | } | |
3166 | ||
54f81859 MW |
3167 | METHOD(kernel_ipsec_t, destroy, void, |
3168 | private_kernel_pfkey_ipsec_t *this) | |
3169 | { | |
d6a27ec6 MW |
3170 | if (this->socket > 0) |
3171 | { | |
3172 | close(this->socket); | |
3173 | } | |
3174 | if (this->socket_events > 0) | |
3175 | { | |
7f698dae | 3176 | lib->watcher->remove(lib->watcher, this->socket_events); |
d6a27ec6 MW |
3177 | close(this->socket_events); |
3178 | } | |
8a2e4d4a | 3179 | this->policies->invoke_function(this->policies, policy_entry_destroy_cb, |
17927ca6 TB |
3180 | this); |
3181 | this->policies->destroy(this->policies); | |
df919d50 | 3182 | this->excludes->destroy(this->excludes); |
17927ca6 | 3183 | this->sas->destroy(this->sas); |
54f81859 MW |
3184 | this->mutex->destroy(this->mutex); |
3185 | this->mutex_pfkey->destroy(this->mutex_pfkey); | |
3186 | free(this); | |
ea625fab TB |
3187 | } |
3188 | ||
1adaa02b TB |
3189 | /* |
3190 | * Described in header. | |
3191 | */ | |
3192 | kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() | |
3193 | { | |
44791b75 | 3194 | private_kernel_pfkey_ipsec_t *this; |
05ca5655 | 3195 | bool register_for_events = TRUE; |
96e61305 | 3196 | int rcv_buffer; |
44791b75 MW |
3197 | |
3198 | INIT(this, | |
ba31fe1f MW |
3199 | .public = { |
3200 | .interface = { | |
3201 | .get_spi = _get_spi, | |
3202 | .get_cpi = _get_cpi, | |
3203 | .add_sa = _add_sa, | |
3204 | .update_sa = _update_sa, | |
3205 | .query_sa = _query_sa, | |
3206 | .del_sa = _del_sa, | |
773572f9 | 3207 | .flush_sas = _flush_sas, |
ba31fe1f MW |
3208 | .add_policy = _add_policy, |
3209 | .query_policy = _query_policy, | |
3210 | .del_policy = _del_policy, | |
773572f9 | 3211 | .flush_policies = _flush_policies, |
ba31fe1f | 3212 | .bypass_socket = _bypass_socket, |
e49abced | 3213 | .enable_udp_decap = _enable_udp_decap, |
ba31fe1f MW |
3214 | .destroy = _destroy, |
3215 | }, | |
44791b75 MW |
3216 | }, |
3217 | .policies = linked_list_create(), | |
df919d50 | 3218 | .excludes = linked_list_create(), |
17927ca6 TB |
3219 | .sas = hashtable_create((hashtable_hash_t)ipsec_sa_hash, |
3220 | (hashtable_equals_t)ipsec_sa_equals, 32), | |
44791b75 MW |
3221 | .mutex = mutex_create(MUTEX_TYPE_DEFAULT), |
3222 | .mutex_pfkey = mutex_create(MUTEX_TYPE_DEFAULT), | |
3223 | .install_routes = lib->settings->get_bool(lib->settings, | |
06cdeac2 | 3224 | "%s.install_routes", TRUE, |
d347a130 | 3225 | lib->ns), |
e8116593 TB |
3226 | .route_via_internal = lib->settings->get_bool(lib->settings, |
3227 | "%s.plugins.kernel-pfkey.route_via_internal", | |
3228 | FALSE, lib->ns), | |
44791b75 | 3229 | ); |
7daf5226 | 3230 | |
d347a130 | 3231 | if (streq(lib->ns, "starter")) |
05ca5655 TB |
3232 | { /* starter has no threads, so we do not register for kernel events */ |
3233 | register_for_events = FALSE; | |
3234 | } | |
b8bf01dd | 3235 | |
1adaa02b TB |
3236 | /* create a PF_KEY socket to communicate with the kernel */ |
3237 | this->socket = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); | |
3238 | if (this->socket <= 0) | |
3239 | { | |
d6a27ec6 MW |
3240 | DBG1(DBG_KNL, "unable to create PF_KEY socket"); |
3241 | destroy(this); | |
3242 | return NULL; | |
1adaa02b | 3243 | } |
7daf5226 | 3244 | |
05ca5655 | 3245 | if (register_for_events) |
1adaa02b | 3246 | { |
05ca5655 TB |
3247 | /* create a PF_KEY socket for ACQUIRE & EXPIRE */ |
3248 | this->socket_events = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); | |
3249 | if (this->socket_events <= 0) | |
3250 | { | |
3251 | DBG1(DBG_KNL, "unable to create PF_KEY event socket"); | |
3252 | destroy(this); | |
3253 | return NULL; | |
3254 | } | |
7daf5226 | 3255 | |
96e61305 TB |
3256 | rcv_buffer = lib->settings->get_int(lib->settings, |
3257 | "%s.plugins.kernel-pfkey.events_buffer_size", 0, lib->ns); | |
3258 | if (rcv_buffer > 0) | |
3259 | { | |
3260 | if (setsockopt(this->socket_events, SOL_SOCKET, SO_RCVBUF, | |
3261 | &rcv_buffer, sizeof(rcv_buffer)) == -1) | |
3262 | { | |
3263 | DBG1(DBG_KNL, "unable to set receive buffer size on PF_KEY " | |
3264 | "event socket: %s", strerror(errno)); | |
3265 | } | |
3266 | } | |
3267 | ||
05ca5655 TB |
3268 | /* register the event socket */ |
3269 | if (register_pfkey_socket(this, SADB_SATYPE_ESP) != SUCCESS || | |
3270 | register_pfkey_socket(this, SADB_SATYPE_AH) != SUCCESS) | |
3271 | { | |
3272 | DBG1(DBG_KNL, "unable to register PF_KEY event socket"); | |
3273 | destroy(this); | |
3274 | return NULL; | |
3275 | } | |
7daf5226 | 3276 | |
7f698dae MW |
3277 | lib->watcher->add(lib->watcher, this->socket_events, WATCHER_READ, |
3278 | (watcher_cb_t)receive_events, this); | |
05ca5655 | 3279 | } |
7daf5226 | 3280 | |
1adaa02b TB |
3281 | return &this->public; |
3282 | } |