]>
Commit | Line | Data |
---|---|---|
507f26f6 | 1 | /* |
888af963 | 2 | * Copyright (C) 2006-2009 Tobias Brunner |
469083cc | 3 | * Copyright (C) 2005-2009 Martin Willi |
c6362858 | 4 | * Copyright (C) 2008 Andreas Steffen |
507f26f6 TB |
5 | * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser |
6 | * Copyright (C) 2006 Daniel Roethlisberger | |
7 | * Copyright (C) 2005 Jan Hutter | |
8 | * Hochschule fuer Technik Rapperswil | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify it | |
11 | * under the terms of the GNU General Public License as published by the | |
12 | * Free Software Foundation; either version 2 of the License, or (at your | |
13 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, but | |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 | * for more details. | |
507f26f6 TB |
19 | */ |
20 | ||
21 | #include <sys/types.h> | |
22 | #include <sys/socket.h> | |
ea625fab TB |
23 | #include <stdint.h> |
24 | #include <linux/ipsec.h> | |
507f26f6 TB |
25 | #include <linux/netlink.h> |
26 | #include <linux/rtnetlink.h> | |
27 | #include <linux/xfrm.h> | |
28 | #include <linux/udp.h> | |
507f26f6 TB |
29 | #include <pthread.h> |
30 | #include <unistd.h> | |
31 | #include <errno.h> | |
32 | #include <string.h> | |
469083cc | 33 | #include <fcntl.h> |
507f26f6 TB |
34 | |
35 | #include "kernel_netlink_ipsec.h" | |
36 | #include "kernel_netlink_shared.h" | |
37 | ||
38 | #include <daemon.h> | |
3ac5a0db | 39 | #include <utils/mutex.h> |
3fb404d8 | 40 | #include <utils/hashtable.h> |
507f26f6 TB |
41 | #include <processing/jobs/callback_job.h> |
42 | #include <processing/jobs/acquire_job.h> | |
ef6d339c | 43 | #include <processing/jobs/migrate_job.h> |
507f26f6 TB |
44 | #include <processing/jobs/rekey_child_sa_job.h> |
45 | #include <processing/jobs/delete_child_sa_job.h> | |
aa9a3006 | 46 | #include <processing/jobs/update_sa_job.h> |
507f26f6 TB |
47 | |
48 | /** required for Linux 2.6.26 kernel and later */ | |
49 | #ifndef XFRM_STATE_AF_UNSPEC | |
50 | #define XFRM_STATE_AF_UNSPEC 32 | |
51 | #endif | |
52 | ||
ea625fab | 53 | /** from linux/in.h */ |
4a38687a MW |
54 | #ifndef IP_XFRM_POLICY |
55 | #define IP_XFRM_POLICY 17 | |
ea625fab TB |
56 | #endif |
57 | ||
addfea95 | 58 | /* missing on uclibc */ |
4a38687a MW |
59 | #ifndef IPV6_XFRM_POLICY |
60 | #define IPV6_XFRM_POLICY 34 | |
61 | #endif /*IPV6_XFRM_POLICY*/ | |
addfea95 | 62 | |
507f26f6 TB |
63 | /** default priority of installed policies */ |
64 | #define PRIO_LOW 3000 | |
65 | #define PRIO_HIGH 2000 | |
66 | ||
1087b9ce TB |
67 | /** |
68 | * map the limit for bytes and packets to XFRM_INF per default | |
69 | */ | |
70 | #define XFRM_LIMIT(x) ((x) == 0 ? XFRM_INF : (x)) | |
71 | ||
aa9a3006 MW |
72 | /** |
73 | * Create ORable bitfield of XFRM NL groups | |
74 | */ | |
75 | #define XFRMNLGRP(x) (1<<(XFRMNLGRP_##x-1)) | |
76 | ||
507f26f6 | 77 | /** |
7daf5226 MW |
78 | * returns a pointer to the first rtattr following the nlmsghdr *nlh and the |
79 | * 'usual' netlink data x like 'struct xfrm_usersa_info' | |
507f26f6 TB |
80 | */ |
81 | #define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(x)))) | |
82 | /** | |
83 | * returns a pointer to the next rtattr following rta. | |
84 | * !!! do not use this to parse messages. use RTA_NEXT and RTA_OK instead !!! | |
85 | */ | |
86 | #define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len))) | |
87 | /** | |
7daf5226 MW |
88 | * returns the total size of attached rta data |
89 | * (after 'usual' netlink data x like 'struct xfrm_usersa_info') | |
507f26f6 TB |
90 | */ |
91 | #define XFRM_PAYLOAD(nlh, x) NLMSG_PAYLOAD(nlh, sizeof(x)) | |
92 | ||
93 | typedef struct kernel_algorithm_t kernel_algorithm_t; | |
94 | ||
95 | /** | |
e517b4b1 | 96 | * Mapping of IKEv2 kernel identifier to linux crypto API names |
507f26f6 TB |
97 | */ |
98 | struct kernel_algorithm_t { | |
99 | /** | |
100 | * Identifier specified in IKEv2 | |
101 | */ | |
e517b4b1 | 102 | int ikev2; |
7daf5226 | 103 | |
507f26f6 | 104 | /** |
e517b4b1 | 105 | * Name of the algorithm in linux crypto API |
507f26f6 TB |
106 | */ |
107 | char *name; | |
507f26f6 TB |
108 | }; |
109 | ||
37fbc741 AS |
110 | ENUM(xfrm_msg_names, XFRM_MSG_NEWSA, XFRM_MSG_MAPPING, |
111 | "XFRM_MSG_NEWSA", | |
112 | "XFRM_MSG_DELSA", | |
113 | "XFRM_MSG_GETSA", | |
114 | "XFRM_MSG_NEWPOLICY", | |
115 | "XFRM_MSG_DELPOLICY", | |
116 | "XFRM_MSG_GETPOLICY", | |
117 | "XFRM_MSG_ALLOCSPI", | |
118 | "XFRM_MSG_ACQUIRE", | |
119 | "XFRM_MSG_EXPIRE", | |
120 | "XFRM_MSG_UPDPOLICY", | |
121 | "XFRM_MSG_UPDSA", | |
122 | "XFRM_MSG_POLEXPIRE", | |
123 | "XFRM_MSG_FLUSHSA", | |
124 | "XFRM_MSG_FLUSHPOLICY", | |
125 | "XFRM_MSG_NEWAE", | |
126 | "XFRM_MSG_GETAE", | |
127 | "XFRM_MSG_REPORT", | |
128 | "XFRM_MSG_MIGRATE", | |
129 | "XFRM_MSG_NEWSADINFO", | |
130 | "XFRM_MSG_GETSADINFO", | |
131 | "XFRM_MSG_NEWSPDINFO", | |
132 | "XFRM_MSG_GETSPDINFO", | |
133 | "XFRM_MSG_MAPPING" | |
134 | ); | |
135 | ||
b74bc438 AS |
136 | ENUM(xfrm_attr_type_names, XFRMA_UNSPEC, XFRMA_KMADDRESS, |
137 | "XFRMA_UNSPEC", | |
138 | "XFRMA_ALG_AUTH", | |
139 | "XFRMA_ALG_CRYPT", | |
140 | "XFRMA_ALG_COMP", | |
141 | "XFRMA_ENCAP", | |
142 | "XFRMA_TMPL", | |
143 | "XFRMA_SA", | |
144 | "XFRMA_POLICY", | |
145 | "XFRMA_SEC_CTX", | |
146 | "XFRMA_LTIME_VAL", | |
147 | "XFRMA_REPLAY_VAL", | |
148 | "XFRMA_REPLAY_THRESH", | |
149 | "XFRMA_ETIMER_THRESH", | |
150 | "XFRMA_SRCADDR", | |
151 | "XFRMA_COADDR", | |
152 | "XFRMA_LASTUSED", | |
153 | "XFRMA_POLICY_TYPE", | |
154 | "XFRMA_MIGRATE", | |
155 | "XFRMA_ALG_AEAD", | |
156 | "XFRMA_KMADDRESS" | |
157 | ); | |
158 | ||
507f26f6 TB |
159 | #define END_OF_LIST -1 |
160 | ||
161 | /** | |
162 | * Algorithms for encryption | |
163 | */ | |
164 | static kernel_algorithm_t encryption_algs[] = { | |
e517b4b1 MW |
165 | /* {ENCR_DES_IV64, "***" }, */ |
166 | {ENCR_DES, "des" }, | |
167 | {ENCR_3DES, "des3_ede" }, | |
168 | /* {ENCR_RC5, "***" }, */ | |
169 | /* {ENCR_IDEA, "***" }, */ | |
170 | {ENCR_CAST, "cast128" }, | |
171 | {ENCR_BLOWFISH, "blowfish" }, | |
172 | /* {ENCR_3IDEA, "***" }, */ | |
173 | /* {ENCR_DES_IV32, "***" }, */ | |
174 | {ENCR_NULL, "cipher_null" }, | |
b9b8a98f | 175 | {ENCR_AES_CBC, "aes" }, |
18eef5d6 | 176 | {ENCR_AES_CTR, "rfc3686(ctr(aes))" }, |
e517b4b1 MW |
177 | {ENCR_AES_CCM_ICV8, "rfc4309(ccm(aes))" }, |
178 | {ENCR_AES_CCM_ICV12, "rfc4309(ccm(aes))" }, | |
179 | {ENCR_AES_CCM_ICV16, "rfc4309(ccm(aes))" }, | |
180 | {ENCR_AES_GCM_ICV8, "rfc4106(gcm(aes))" }, | |
181 | {ENCR_AES_GCM_ICV12, "rfc4106(gcm(aes))" }, | |
182 | {ENCR_AES_GCM_ICV16, "rfc4106(gcm(aes))" }, | |
247e665a AS |
183 | /* {ENCR_NULL_AUTH_AES_GMAC, "***" }, */ |
184 | {ENCR_CAMELLIA_CBC, "cbc(camellia)" }, | |
185 | /* {ENCR_CAMELLIA_CTR, "***" }, */ | |
186 | /* {ENCR_CAMELLIA_CCM_ICV8, "***" }, */ | |
187 | /* {ENCR_CAMELLIA_CCM_ICV12, "***" }, */ | |
188 | /* {ENCR_CAMELLIA_CCM_ICV16, "***" }, */ | |
189 | {END_OF_LIST, NULL } | |
507f26f6 TB |
190 | }; |
191 | ||
192 | /** | |
193 | * Algorithms for integrity protection | |
194 | */ | |
195 | static kernel_algorithm_t integrity_algs[] = { | |
e517b4b1 MW |
196 | {AUTH_HMAC_MD5_96, "md5" }, |
197 | {AUTH_HMAC_SHA1_96, "sha1" }, | |
6546482a | 198 | {AUTH_HMAC_SHA2_256_96, "sha256" }, |
6780edc0 MW |
199 | {AUTH_HMAC_SHA2_384_192, "hmac(sha384)" }, |
200 | {AUTH_HMAC_SHA2_512_256, "hmac(sha512)" }, | |
e517b4b1 MW |
201 | /* {AUTH_DES_MAC, "***" }, */ |
202 | /* {AUTH_KPDK_MD5, "***" }, */ | |
203 | {AUTH_AES_XCBC_96, "xcbc(aes)" }, | |
247e665a | 204 | {END_OF_LIST, NULL } |
507f26f6 TB |
205 | }; |
206 | ||
207 | /** | |
208 | * Algorithms for IPComp | |
209 | */ | |
210 | static kernel_algorithm_t compression_algs[] = { | |
e517b4b1 MW |
211 | /* {IPCOMP_OUI, "***" }, */ |
212 | {IPCOMP_DEFLATE, "deflate" }, | |
213 | {IPCOMP_LZS, "lzs" }, | |
214 | {IPCOMP_LZJH, "lzjh" }, | |
247e665a | 215 | {END_OF_LIST, NULL } |
507f26f6 TB |
216 | }; |
217 | ||
218 | /** | |
219 | * Look up a kernel algorithm name and its key size | |
220 | */ | |
e517b4b1 | 221 | static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2) |
507f26f6 | 222 | { |
e517b4b1 | 223 | while (list->ikev2 != END_OF_LIST) |
507f26f6 | 224 | { |
e517b4b1 | 225 | if (list->ikev2 == ikev2) |
507f26f6 | 226 | { |
e517b4b1 | 227 | return list->name; |
507f26f6 | 228 | } |
e517b4b1 | 229 | list++; |
507f26f6 TB |
230 | } |
231 | return NULL; | |
232 | } | |
233 | ||
234 | typedef struct route_entry_t route_entry_t; | |
235 | ||
236 | /** | |
237 | * installed routing entry | |
238 | */ | |
239 | struct route_entry_t { | |
240 | /** Name of the interface the route is bound to */ | |
241 | char *if_name; | |
7daf5226 | 242 | |
507f26f6 TB |
243 | /** Source ip of the route */ |
244 | host_t *src_ip; | |
7daf5226 | 245 | |
507f26f6 TB |
246 | /** gateway for this route */ |
247 | host_t *gateway; | |
248 | ||
249 | /** Destination net */ | |
250 | chunk_t dst_net; | |
251 | ||
252 | /** Destination net prefixlen */ | |
253 | u_int8_t prefixlen; | |
254 | }; | |
255 | ||
256 | /** | |
257 | * destroy an route_entry_t object | |
258 | */ | |
259 | static void route_entry_destroy(route_entry_t *this) | |
260 | { | |
261 | free(this->if_name); | |
262 | this->src_ip->destroy(this->src_ip); | |
5be75c2c | 263 | DESTROY_IF(this->gateway); |
507f26f6 TB |
264 | chunk_free(&this->dst_net); |
265 | free(this); | |
266 | } | |
267 | ||
268 | typedef struct policy_entry_t policy_entry_t; | |
269 | ||
270 | /** | |
271 | * installed kernel policy. | |
272 | */ | |
273 | struct policy_entry_t { | |
7daf5226 | 274 | |
507f26f6 TB |
275 | /** direction of this policy: in, out, forward */ |
276 | u_int8_t direction; | |
7daf5226 | 277 | |
507f26f6 TB |
278 | /** parameters of installed policy */ |
279 | struct xfrm_selector sel; | |
7daf5226 | 280 | |
507f26f6 TB |
281 | /** associated route installed for this policy */ |
282 | route_entry_t *route; | |
7daf5226 | 283 | |
507f26f6 TB |
284 | /** by how many CHILD_SA's this policy is used */ |
285 | u_int refcount; | |
286 | }; | |
287 | ||
3fb404d8 TB |
288 | /** |
289 | * Hash function for policy_entry_t objects | |
290 | */ | |
291 | static u_int policy_hash(policy_entry_t *key) | |
292 | { | |
293 | chunk_t chunk = chunk_create((void*)&key->sel, sizeof(struct xfrm_selector)); | |
294 | return chunk_hash(chunk); | |
295 | } | |
296 | ||
297 | /** | |
298 | * Equality function for policy_entry_t objects | |
299 | */ | |
300 | static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key) | |
301 | { | |
302 | return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) && | |
303 | key->direction == other_key->direction; | |
304 | } | |
305 | ||
507f26f6 TB |
306 | typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t; |
307 | ||
308 | /** | |
309 | * Private variables and functions of kernel_netlink class. | |
310 | */ | |
311 | struct private_kernel_netlink_ipsec_t { | |
312 | /** | |
313 | * Public part of the kernel_netlink_t object. | |
314 | */ | |
315 | kernel_netlink_ipsec_t public; | |
7daf5226 | 316 | |
507f26f6 TB |
317 | /** |
318 | * mutex to lock access to various lists | |
319 | */ | |
3ac5a0db | 320 | mutex_t *mutex; |
7daf5226 | 321 | |
507f26f6 | 322 | /** |
3fb404d8 | 323 | * Hash table of installed policies (policy_entry_t) |
507f26f6 | 324 | */ |
3fb404d8 | 325 | hashtable_t *policies; |
7daf5226 | 326 | |
507f26f6 TB |
327 | /** |
328 | * job receiving netlink events | |
329 | */ | |
330 | callback_job_t *job; | |
7daf5226 | 331 | |
507f26f6 TB |
332 | /** |
333 | * Netlink xfrm socket (IPsec) | |
334 | */ | |
335 | netlink_socket_t *socket_xfrm; | |
7daf5226 | 336 | |
507f26f6 TB |
337 | /** |
338 | * netlink xfrm socket to receive acquire and expire events | |
339 | */ | |
340 | int socket_xfrm_events; | |
7daf5226 | 341 | |
507f26f6 TB |
342 | /** |
343 | * whether to install routes along policies | |
344 | */ | |
345 | bool install_routes; | |
346 | }; | |
347 | ||
348 | /** | |
349 | * convert a IKEv2 specific protocol identifier to the kernel one | |
350 | */ | |
351 | static u_int8_t proto_ike2kernel(protocol_id_t proto) | |
352 | { | |
353 | switch (proto) | |
354 | { | |
355 | case PROTO_ESP: | |
356 | return IPPROTO_ESP; | |
357 | case PROTO_AH: | |
358 | return IPPROTO_AH; | |
359 | default: | |
360 | return proto; | |
361 | } | |
362 | } | |
363 | ||
364 | /** | |
365 | * reverse of ike2kernel | |
366 | */ | |
367 | static protocol_id_t proto_kernel2ike(u_int8_t proto) | |
368 | { | |
369 | switch (proto) | |
370 | { | |
371 | case IPPROTO_ESP: | |
372 | return PROTO_ESP; | |
373 | case IPPROTO_AH: | |
374 | return PROTO_AH; | |
375 | default: | |
376 | return proto; | |
377 | } | |
378 | } | |
379 | ||
d24a74c5 TB |
380 | /** |
381 | * convert the general ipsec mode to the one defined in xfrm.h | |
382 | */ | |
383 | static u_int8_t mode2kernel(ipsec_mode_t mode) | |
384 | { | |
385 | switch (mode) | |
386 | { | |
387 | case MODE_TRANSPORT: | |
388 | return XFRM_MODE_TRANSPORT; | |
389 | case MODE_TUNNEL: | |
390 | return XFRM_MODE_TUNNEL; | |
391 | case MODE_BEET: | |
392 | return XFRM_MODE_BEET; | |
393 | default: | |
394 | return mode; | |
395 | } | |
396 | } | |
397 | ||
507f26f6 TB |
398 | /** |
399 | * convert a host_t to a struct xfrm_address | |
400 | */ | |
401 | static void host2xfrm(host_t *host, xfrm_address_t *xfrm) | |
402 | { | |
403 | chunk_t chunk = host->get_address(host); | |
7daf5226 | 404 | memcpy(xfrm, chunk.ptr, min(chunk.len, sizeof(xfrm_address_t))); |
507f26f6 TB |
405 | } |
406 | ||
aa9a3006 MW |
407 | /** |
408 | * convert a struct xfrm_address to a host_t | |
409 | */ | |
410 | static host_t* xfrm2host(int family, xfrm_address_t *xfrm, u_int16_t port) | |
411 | { | |
412 | chunk_t chunk; | |
7daf5226 | 413 | |
aa9a3006 MW |
414 | switch (family) |
415 | { | |
416 | case AF_INET: | |
417 | chunk = chunk_create((u_char*)&xfrm->a4, sizeof(xfrm->a4)); | |
418 | break; | |
419 | case AF_INET6: | |
420 | chunk = chunk_create((u_char*)&xfrm->a6, sizeof(xfrm->a6)); | |
421 | break; | |
422 | default: | |
423 | return NULL; | |
424 | } | |
425 | return host_create_from_chunk(family, chunk, ntohs(port)); | |
426 | } | |
427 | ||
507f26f6 TB |
428 | /** |
429 | * convert a traffic selector address range to subnet and its mask. | |
430 | */ | |
7daf5226 | 431 | static void ts2subnet(traffic_selector_t* ts, |
507f26f6 TB |
432 | xfrm_address_t *net, u_int8_t *mask) |
433 | { | |
1adaa02b TB |
434 | host_t *net_host; |
435 | chunk_t net_chunk; | |
7daf5226 | 436 | |
1adaa02b TB |
437 | ts->to_subnet(ts, &net_host, mask); |
438 | net_chunk = net_host->get_address(net_host); | |
439 | memcpy(net, net_chunk.ptr, net_chunk.len); | |
440 | net_host->destroy(net_host); | |
507f26f6 TB |
441 | } |
442 | ||
443 | /** | |
444 | * convert a traffic selector port range to port/portmask | |
445 | */ | |
7daf5226 | 446 | static void ts2ports(traffic_selector_t* ts, |
507f26f6 TB |
447 | u_int16_t *port, u_int16_t *mask) |
448 | { | |
449 | /* linux does not seem to accept complex portmasks. Only | |
450 | * any or a specific port is allowed. We set to any, if we have | |
451 | * a port range, or to a specific, if we have one port only. | |
452 | */ | |
453 | u_int16_t from, to; | |
7daf5226 | 454 | |
507f26f6 TB |
455 | from = ts->get_from_port(ts); |
456 | to = ts->get_to_port(ts); | |
7daf5226 | 457 | |
507f26f6 TB |
458 | if (from == to) |
459 | { | |
460 | *port = htons(from); | |
461 | *mask = ~0; | |
462 | } | |
463 | else | |
464 | { | |
465 | *port = 0; | |
466 | *mask = 0; | |
467 | } | |
468 | } | |
469 | ||
470 | /** | |
471 | * convert a pair of traffic_selectors to a xfrm_selector | |
472 | */ | |
7daf5226 | 473 | static struct xfrm_selector ts2selector(traffic_selector_t *src, |
507f26f6 TB |
474 | traffic_selector_t *dst) |
475 | { | |
476 | struct xfrm_selector sel; | |
477 | ||
478 | memset(&sel, 0, sizeof(sel)); | |
479 | sel.family = (src->get_type(src) == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; | |
480 | /* src or dest proto may be "any" (0), use more restrictive one */ | |
481 | sel.proto = max(src->get_protocol(src), dst->get_protocol(dst)); | |
482 | ts2subnet(dst, &sel.daddr, &sel.prefixlen_d); | |
483 | ts2subnet(src, &sel.saddr, &sel.prefixlen_s); | |
484 | ts2ports(dst, &sel.dport, &sel.dport_mask); | |
485 | ts2ports(src, &sel.sport, &sel.sport_mask); | |
486 | sel.ifindex = 0; | |
487 | sel.user = 0; | |
7daf5226 | 488 | |
507f26f6 TB |
489 | return sel; |
490 | } | |
491 | ||
e526d228 | 492 | /** |
7daf5226 | 493 | * convert a xfrm_selector to a src|dst traffic_selector |
e526d228 AS |
494 | */ |
495 | static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src) | |
496 | { | |
70691c31 | 497 | u_char *addr; |
5145ae48 | 498 | u_int8_t prefixlen; |
70691c31 MW |
499 | u_int16_t port = 0; |
500 | host_t *host = NULL; | |
7daf5226 | 501 | |
e526d228 AS |
502 | if (src) |
503 | { | |
70691c31 | 504 | addr = (u_char*)&sel->saddr; |
5145ae48 | 505 | prefixlen = sel->prefixlen_s; |
70691c31 MW |
506 | if (sel->sport_mask) |
507 | { | |
508 | port = htons(sel->sport); | |
509 | } | |
e526d228 | 510 | } |
70691c31 | 511 | else |
e526d228 | 512 | { |
70691c31 | 513 | addr = (u_char*)&sel->daddr; |
5145ae48 | 514 | prefixlen = sel->prefixlen_d; |
70691c31 MW |
515 | if (sel->dport_mask) |
516 | { | |
517 | port = htons(sel->dport); | |
518 | } | |
e526d228 | 519 | } |
7daf5226 | 520 | |
e526d228 | 521 | /* The Linux 2.6 kernel does not set the selector's family field, |
7daf5226 | 522 | * so as a kludge we additionally test the prefix length. |
e526d228 | 523 | */ |
b74bc438 | 524 | if (sel->family == AF_INET || sel->prefixlen_s == 32) |
e526d228 | 525 | { |
70691c31 | 526 | host = host_create_from_chunk(AF_INET, chunk_create(addr, 4), 0); |
e526d228 | 527 | } |
b74bc438 | 528 | else if (sel->family == AF_INET6 || sel->prefixlen_s == 128) |
e526d228 | 529 | { |
70691c31 | 530 | host = host_create_from_chunk(AF_INET6, chunk_create(addr, 16), 0); |
b74bc438 | 531 | } |
7daf5226 | 532 | |
70691c31 | 533 | if (host) |
b74bc438 | 534 | { |
70691c31 MW |
535 | return traffic_selector_create_from_subnet(host, prefixlen, |
536 | sel->proto, port); | |
b74bc438 | 537 | } |
70691c31 | 538 | return NULL; |
e526d228 | 539 | } |
507f26f6 TB |
540 | |
541 | /** | |
542 | * process a XFRM_MSG_ACQUIRE from kernel | |
543 | */ | |
544 | static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr) | |
545 | { | |
546 | u_int32_t reqid = 0; | |
547 | int proto = 0; | |
e526d228 AS |
548 | traffic_selector_t *src_ts, *dst_ts; |
549 | struct xfrm_user_acquire *acquire; | |
b74bc438 AS |
550 | struct rtattr *rta; |
551 | size_t rtasize; | |
507f26f6 | 552 | job_t *job; |
7daf5226 | 553 | |
b74bc438 AS |
554 | acquire = (struct xfrm_user_acquire*)NLMSG_DATA(hdr); |
555 | rta = XFRM_RTA(hdr, struct xfrm_user_acquire); | |
556 | rtasize = XFRM_PAYLOAD(hdr, struct xfrm_user_acquire); | |
557 | ||
558 | DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE"); | |
e526d228 | 559 | |
b74bc438 | 560 | while (RTA_OK(rta, rtasize)) |
507f26f6 | 561 | { |
b74bc438 AS |
562 | DBG2(DBG_KNL, " %N", xfrm_attr_type_names, rta->rta_type); |
563 | ||
564 | if (rta->rta_type == XFRMA_TMPL) | |
507f26f6 | 565 | { |
e526d228 AS |
566 | struct xfrm_user_tmpl* tmpl; |
567 | ||
b74bc438 | 568 | tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rta); |
507f26f6 TB |
569 | reqid = tmpl->reqid; |
570 | proto = tmpl->id.proto; | |
571 | } | |
b74bc438 | 572 | rta = RTA_NEXT(rta, rtasize); |
507f26f6 TB |
573 | } |
574 | switch (proto) | |
575 | { | |
576 | case 0: | |
577 | case IPPROTO_ESP: | |
578 | case IPPROTO_AH: | |
579 | break; | |
580 | default: | |
581 | /* acquire for AH/ESP only, not for IPCOMP */ | |
582 | return; | |
583 | } | |
e526d228 AS |
584 | src_ts = selector2ts(&acquire->sel, TRUE); |
585 | dst_ts = selector2ts(&acquire->sel, FALSE); | |
ef6d339c | 586 | DBG1(DBG_KNL, "creating acquire job for policy %R === %R with reqid {%u}", |
e526d228 AS |
587 | src_ts, dst_ts, reqid); |
588 | job = (job_t*)acquire_job_create(reqid, src_ts, dst_ts); | |
507f26f6 TB |
589 | charon->processor->queue_job(charon->processor, job); |
590 | } | |
591 | ||
592 | /** | |
593 | * process a XFRM_MSG_EXPIRE from kernel | |
594 | */ | |
595 | static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr) | |
596 | { | |
597 | job_t *job; | |
598 | protocol_id_t protocol; | |
599 | u_int32_t spi, reqid; | |
600 | struct xfrm_user_expire *expire; | |
7daf5226 | 601 | |
507f26f6 TB |
602 | expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr); |
603 | protocol = proto_kernel2ike(expire->state.id.proto); | |
604 | spi = expire->state.id.spi; | |
605 | reqid = expire->state.reqid; | |
7daf5226 | 606 | |
507f26f6 | 607 | DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE"); |
7daf5226 | 608 | |
507f26f6 TB |
609 | if (protocol != PROTO_ESP && protocol != PROTO_AH) |
610 | { | |
ef6d339c | 611 | DBG2(DBG_KNL, "ignoring XFRM_MSG_EXPIRE for SA with SPI %.8x and reqid {%u} " |
507f26f6 TB |
612 | "which is not a CHILD_SA", ntohl(spi), reqid); |
613 | return; | |
614 | } | |
7daf5226 | 615 | |
507f26f6 TB |
616 | DBG1(DBG_KNL, "creating %s job for %N CHILD_SA with SPI %.8x and reqid {%d}", |
617 | expire->hard ? "delete" : "rekey", protocol_id_names, | |
618 | protocol, ntohl(spi), reqid); | |
619 | if (expire->hard) | |
620 | { | |
621 | job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi); | |
622 | } | |
623 | else | |
624 | { | |
625 | job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi); | |
626 | } | |
627 | charon->processor->queue_job(charon->processor, job); | |
628 | } | |
629 | ||
e526d228 AS |
630 | /** |
631 | * process a XFRM_MSG_MIGRATE from kernel | |
632 | */ | |
633 | static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr) | |
634 | { | |
5145ae48 AS |
635 | traffic_selector_t *src_ts, *dst_ts; |
636 | host_t *local = NULL, *remote = NULL; | |
637 | host_t *old_src = NULL, *old_dst = NULL; | |
638 | host_t *new_src = NULL, *new_dst = NULL; | |
639 | struct xfrm_userpolicy_id *policy_id; | |
b74bc438 AS |
640 | struct rtattr *rta; |
641 | size_t rtasize; | |
5145ae48 | 642 | u_int32_t reqid = 0; |
ef6d339c | 643 | policy_dir_t dir; |
5145ae48 | 644 | job_t *job; |
b74bc438 | 645 | |
5145ae48 | 646 | policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr); |
b74bc438 AS |
647 | rta = XFRM_RTA(hdr, struct xfrm_userpolicy_id); |
648 | rtasize = XFRM_PAYLOAD(hdr, struct xfrm_userpolicy_id); | |
649 | ||
e526d228 | 650 | DBG2(DBG_KNL, "received a XFRM_MSG_MIGRATE"); |
7daf5226 | 651 | |
5145ae48 AS |
652 | src_ts = selector2ts(&policy_id->sel, TRUE); |
653 | dst_ts = selector2ts(&policy_id->sel, FALSE); | |
ef6d339c AS |
654 | dir = (policy_dir_t)policy_id->dir; |
655 | ||
7a915d62 | 656 | DBG2(DBG_KNL, " policy: %R === %R %N", src_ts, dst_ts, policy_dir_names); |
b74bc438 AS |
657 | |
658 | while (RTA_OK(rta, rtasize)) | |
659 | { | |
5145ae48 AS |
660 | DBG2(DBG_KNL, " %N", xfrm_attr_type_names, rta->rta_type); |
661 | if (rta->rta_type == XFRMA_KMADDRESS) | |
662 | { | |
663 | struct xfrm_user_kmaddress *kmaddress; | |
664 | ||
665 | kmaddress = (struct xfrm_user_kmaddress*)RTA_DATA(rta); | |
666 | local = xfrm2host(kmaddress->family, &kmaddress->local, 0); | |
667 | remote = xfrm2host(kmaddress->family, &kmaddress->remote, 0); | |
2c815393 | 668 | DBG2(DBG_KNL, " kmaddress: %H...%H", local, remote); |
bab075b1 | 669 | } |
5145ae48 AS |
670 | else if (rta->rta_type == XFRMA_MIGRATE) |
671 | { | |
672 | struct xfrm_user_migrate *migrate; | |
673 | protocol_id_t proto; | |
674 | ||
675 | migrate = (struct xfrm_user_migrate*)RTA_DATA(rta); | |
676 | old_src = xfrm2host(migrate->old_family, &migrate->old_saddr, 0); | |
677 | old_dst = xfrm2host(migrate->old_family, &migrate->old_daddr, 0); | |
678 | new_src = xfrm2host(migrate->new_family, &migrate->new_saddr, 0); | |
679 | new_dst = xfrm2host(migrate->new_family, &migrate->new_daddr, 0); | |
680 | proto = proto_kernel2ike(migrate->proto); | |
681 | reqid = migrate->reqid; | |
682 | DBG2(DBG_KNL, " migrate %N %H...%H to %H...%H, reqid {%u}", | |
683 | protocol_id_names, proto, old_src, old_dst, | |
ec1bddc5 | 684 | new_src, new_dst, reqid); |
5145ae48 AS |
685 | DESTROY_IF(old_src); |
686 | DESTROY_IF(old_dst); | |
687 | DESTROY_IF(new_src); | |
688 | DESTROY_IF(new_dst); | |
689 | } | |
b74bc438 AS |
690 | rta = RTA_NEXT(rta, rtasize); |
691 | } | |
ef6d339c | 692 | |
7a915d62 | 693 | if (src_ts && dst_ts && local && remote) |
ef6d339c | 694 | { |
bab075b1 | 695 | DBG1(DBG_KNL, "creating migrate job for policy %R === %R %N with reqid {%u}", |
ef6d339c | 696 | src_ts, dst_ts, policy_dir_names, dir, reqid, local); |
bab075b1 AS |
697 | job = (job_t*)migrate_job_create(reqid, src_ts, dst_ts, dir, |
698 | local, remote); | |
ef6d339c AS |
699 | charon->processor->queue_job(charon->processor, job); |
700 | } | |
701 | else | |
702 | { | |
703 | DESTROY_IF(src_ts); | |
704 | DESTROY_IF(dst_ts); | |
705 | DESTROY_IF(local); | |
bab075b1 | 706 | DESTROY_IF(remote); |
ef6d339c | 707 | } |
e526d228 AS |
708 | } |
709 | ||
aa9a3006 MW |
710 | /** |
711 | * process a XFRM_MSG_MAPPING from kernel | |
712 | */ | |
713 | static void process_mapping(private_kernel_netlink_ipsec_t *this, | |
714 | struct nlmsghdr *hdr) | |
715 | { | |
716 | job_t *job; | |
717 | u_int32_t spi, reqid; | |
718 | struct xfrm_user_mapping *mapping; | |
719 | host_t *host; | |
7daf5226 | 720 | |
aa9a3006 MW |
721 | mapping = (struct xfrm_user_mapping*)NLMSG_DATA(hdr); |
722 | spi = mapping->id.spi; | |
723 | reqid = mapping->reqid; | |
7daf5226 | 724 | |
aa9a3006 | 725 | DBG2(DBG_KNL, "received a XFRM_MSG_MAPPING"); |
7daf5226 | 726 | |
aa9a3006 MW |
727 | if (proto_kernel2ike(mapping->id.proto) == PROTO_ESP) |
728 | { | |
729 | host = xfrm2host(mapping->id.family, &mapping->new_saddr, | |
730 | mapping->new_sport); | |
731 | if (host) | |
732 | { | |
733 | DBG1(DBG_KNL, "NAT mappings of ESP CHILD_SA with SPI %.8x and " | |
ef6d339c | 734 | "reqid {%u} changed, queuing update job", ntohl(spi), reqid); |
aa9a3006 MW |
735 | job = (job_t*)update_sa_job_create(reqid, host); |
736 | charon->processor->queue_job(charon->processor, job); | |
737 | } | |
738 | } | |
739 | } | |
740 | ||
507f26f6 TB |
741 | /** |
742 | * Receives events from kernel | |
743 | */ | |
744 | static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this) | |
745 | { | |
746 | char response[1024]; | |
747 | struct nlmsghdr *hdr = (struct nlmsghdr*)response; | |
748 | struct sockaddr_nl addr; | |
749 | socklen_t addr_len = sizeof(addr); | |
750 | int len, oldstate; | |
751 | ||
752 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); | |
753 | len = recvfrom(this->socket_xfrm_events, response, sizeof(response), 0, | |
754 | (struct sockaddr*)&addr, &addr_len); | |
755 | pthread_setcancelstate(oldstate, NULL); | |
7daf5226 | 756 | |
507f26f6 TB |
757 | if (len < 0) |
758 | { | |
759 | switch (errno) | |
760 | { | |
761 | case EINTR: | |
762 | /* interrupted, try again */ | |
763 | return JOB_REQUEUE_DIRECT; | |
764 | case EAGAIN: | |
765 | /* no data ready, select again */ | |
766 | return JOB_REQUEUE_DIRECT; | |
767 | default: | |
768 | DBG1(DBG_KNL, "unable to receive from xfrm event socket"); | |
769 | sleep(1); | |
770 | return JOB_REQUEUE_FAIR; | |
771 | } | |
772 | } | |
7daf5226 | 773 | |
507f26f6 TB |
774 | if (addr.nl_pid != 0) |
775 | { /* not from kernel. not interested, try another one */ | |
776 | return JOB_REQUEUE_DIRECT; | |
777 | } | |
7daf5226 | 778 | |
507f26f6 TB |
779 | while (NLMSG_OK(hdr, len)) |
780 | { | |
781 | switch (hdr->nlmsg_type) | |
782 | { | |
783 | case XFRM_MSG_ACQUIRE: | |
784 | process_acquire(this, hdr); | |
785 | break; | |
786 | case XFRM_MSG_EXPIRE: | |
787 | process_expire(this, hdr); | |
788 | break; | |
e526d228 AS |
789 | case XFRM_MSG_MIGRATE: |
790 | process_migrate(this, hdr); | |
791 | break; | |
aa9a3006 MW |
792 | case XFRM_MSG_MAPPING: |
793 | process_mapping(this, hdr); | |
794 | break; | |
507f26f6 | 795 | default: |
1087b9ce | 796 | DBG1(DBG_KNL, "received unknown event from xfrm event socket: %d", hdr->nlmsg_type); |
507f26f6 TB |
797 | break; |
798 | } | |
799 | hdr = NLMSG_NEXT(hdr, len); | |
800 | } | |
801 | return JOB_REQUEUE_DIRECT; | |
802 | } | |
803 | ||
507f26f6 TB |
804 | /** |
805 | * Get an SPI for a specific protocol from the kernel. | |
806 | */ | |
807 | static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this, | |
808 | host_t *src, host_t *dst, u_int8_t proto, u_int32_t min, u_int32_t max, | |
809 | u_int32_t reqid, u_int32_t *spi) | |
810 | { | |
21bf86f7 | 811 | netlink_buf_t request; |
507f26f6 TB |
812 | struct nlmsghdr *hdr, *out; |
813 | struct xfrm_userspi_info *userspi; | |
814 | u_int32_t received_spi = 0; | |
815 | size_t len; | |
7daf5226 | 816 | |
507f26f6 | 817 | memset(&request, 0, sizeof(request)); |
7daf5226 | 818 | |
507f26f6 TB |
819 | hdr = (struct nlmsghdr*)request; |
820 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
821 | hdr->nlmsg_type = XFRM_MSG_ALLOCSPI; | |
822 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userspi_info)); | |
823 | ||
824 | userspi = (struct xfrm_userspi_info*)NLMSG_DATA(hdr); | |
825 | host2xfrm(src, &userspi->info.saddr); | |
826 | host2xfrm(dst, &userspi->info.id.daddr); | |
827 | userspi->info.id.proto = proto; | |
d24a74c5 | 828 | userspi->info.mode = XFRM_MODE_TUNNEL; |
507f26f6 TB |
829 | userspi->info.reqid = reqid; |
830 | userspi->info.family = src->get_family(src); | |
831 | userspi->min = min; | |
832 | userspi->max = max; | |
7daf5226 | 833 | |
507f26f6 TB |
834 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) |
835 | { | |
836 | hdr = out; | |
837 | while (NLMSG_OK(hdr, len)) | |
838 | { | |
839 | switch (hdr->nlmsg_type) | |
840 | { | |
841 | case XFRM_MSG_NEWSA: | |
842 | { | |
843 | struct xfrm_usersa_info* usersa = NLMSG_DATA(hdr); | |
844 | received_spi = usersa->id.spi; | |
845 | break; | |
846 | } | |
847 | case NLMSG_ERROR: | |
848 | { | |
849 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
7daf5226 | 850 | |
507f26f6 TB |
851 | DBG1(DBG_KNL, "allocating SPI failed: %s (%d)", |
852 | strerror(-err->error), -err->error); | |
853 | break; | |
854 | } | |
855 | default: | |
856 | hdr = NLMSG_NEXT(hdr, len); | |
857 | continue; | |
858 | case NLMSG_DONE: | |
859 | break; | |
860 | } | |
861 | break; | |
862 | } | |
863 | free(out); | |
864 | } | |
7daf5226 | 865 | |
507f26f6 TB |
866 | if (received_spi == 0) |
867 | { | |
868 | return FAILED; | |
869 | } | |
7daf5226 | 870 | |
507f26f6 TB |
871 | *spi = received_spi; |
872 | return SUCCESS; | |
873 | } | |
874 | ||
875 | /** | |
876 | * Implementation of kernel_interface_t.get_spi. | |
877 | */ | |
7daf5226 MW |
878 | static status_t get_spi(private_kernel_netlink_ipsec_t *this, |
879 | host_t *src, host_t *dst, | |
507f26f6 TB |
880 | protocol_id_t protocol, u_int32_t reqid, |
881 | u_int32_t *spi) | |
882 | { | |
ef6d339c | 883 | DBG2(DBG_KNL, "getting SPI for reqid {%u}", reqid); |
7daf5226 | 884 | |
507f26f6 TB |
885 | if (get_spi_internal(this, src, dst, proto_ike2kernel(protocol), |
886 | 0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS) | |
887 | { | |
ef6d339c | 888 | DBG1(DBG_KNL, "unable to get SPI for reqid {%u}", reqid); |
507f26f6 TB |
889 | return FAILED; |
890 | } | |
7daf5226 | 891 | |
ef6d339c | 892 | DBG2(DBG_KNL, "got SPI %.8x for reqid {%u}", ntohl(*spi), reqid); |
7daf5226 | 893 | |
507f26f6 TB |
894 | return SUCCESS; |
895 | } | |
896 | ||
897 | /** | |
898 | * Implementation of kernel_interface_t.get_cpi. | |
899 | */ | |
7daf5226 MW |
900 | static status_t get_cpi(private_kernel_netlink_ipsec_t *this, |
901 | host_t *src, host_t *dst, | |
507f26f6 TB |
902 | u_int32_t reqid, u_int16_t *cpi) |
903 | { | |
904 | u_int32_t received_spi = 0; | |
905 | ||
ef6d339c | 906 | DBG2(DBG_KNL, "getting CPI for reqid {%u}", reqid); |
7daf5226 | 907 | |
507f26f6 TB |
908 | if (get_spi_internal(this, src, dst, |
909 | IPPROTO_COMP, 0x100, 0xEFFF, reqid, &received_spi) != SUCCESS) | |
910 | { | |
ef6d339c | 911 | DBG1(DBG_KNL, "unable to get CPI for reqid {%u}", reqid); |
507f26f6 TB |
912 | return FAILED; |
913 | } | |
7daf5226 | 914 | |
507f26f6 | 915 | *cpi = htons((u_int16_t)ntohl(received_spi)); |
7daf5226 | 916 | |
ef6d339c | 917 | DBG2(DBG_KNL, "got CPI %.4x for reqid {%u}", ntohs(*cpi), reqid); |
7daf5226 | 918 | |
507f26f6 TB |
919 | return SUCCESS; |
920 | } | |
921 | ||
922 | /** | |
923 | * Implementation of kernel_interface_t.add_sa. | |
924 | */ | |
925 | static status_t add_sa(private_kernel_netlink_ipsec_t *this, | |
926 | host_t *src, host_t *dst, u_int32_t spi, | |
927 | protocol_id_t protocol, u_int32_t reqid, | |
888af963 | 928 | lifetime_cfg_t *lifetime, |
e517b4b1 MW |
929 | u_int16_t enc_alg, chunk_t enc_key, |
930 | u_int16_t int_alg, chunk_t int_key, | |
ea625fab TB |
931 | ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, |
932 | bool encap, bool inbound) | |
507f26f6 | 933 | { |
21bf86f7 | 934 | netlink_buf_t request; |
507f26f6 | 935 | char *alg_name; |
507f26f6 TB |
936 | struct nlmsghdr *hdr; |
937 | struct xfrm_usersa_info *sa; | |
7daf5226 MW |
938 | u_int16_t icv_size = 64; |
939 | ||
ea625fab TB |
940 | /* if IPComp is used, we install an additional IPComp SA. if the cpi is 0 |
941 | * we are in the recursive call below */ | |
942 | if (ipcomp != IPCOMP_NONE && cpi != 0) | |
943 | { | |
e75f4237 | 944 | lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}}; |
888af963 | 945 | add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, &lft, |
7b3814f7 MW |
946 | ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty, |
947 | mode, ipcomp, 0, FALSE, inbound); | |
ea625fab | 948 | ipcomp = IPCOMP_NONE; |
2b2c69e9 MW |
949 | /* use transport mode ESP SA, IPComp uses tunnel mode */ |
950 | mode = MODE_TRANSPORT; | |
ea625fab | 951 | } |
7daf5226 | 952 | |
507f26f6 | 953 | memset(&request, 0, sizeof(request)); |
7daf5226 | 954 | |
ef6d339c | 955 | DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", |
e517b4b1 | 956 | ntohl(spi), reqid); |
7daf5226 | 957 | |
507f26f6 TB |
958 | hdr = (struct nlmsghdr*)request; |
959 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
ea625fab | 960 | hdr->nlmsg_type = inbound ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; |
507f26f6 | 961 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); |
7daf5226 | 962 | |
507f26f6 TB |
963 | sa = (struct xfrm_usersa_info*)NLMSG_DATA(hdr); |
964 | host2xfrm(src, &sa->saddr); | |
965 | host2xfrm(dst, &sa->id.daddr); | |
966 | sa->id.spi = spi; | |
967 | sa->id.proto = proto_ike2kernel(protocol); | |
968 | sa->family = src->get_family(src); | |
d24a74c5 | 969 | sa->mode = mode2kernel(mode); |
507f26f6 TB |
970 | if (mode == MODE_TUNNEL) |
971 | { | |
972 | sa->flags |= XFRM_STATE_AF_UNSPEC; | |
973 | } | |
974 | sa->replay_window = (protocol == IPPROTO_COMP) ? 0 : 32; | |
975 | sa->reqid = reqid; | |
e75f4237 TB |
976 | sa->lft.soft_byte_limit = XFRM_LIMIT(lifetime->bytes.rekey); |
977 | sa->lft.hard_byte_limit = XFRM_LIMIT(lifetime->bytes.life); | |
978 | sa->lft.soft_packet_limit = XFRM_LIMIT(lifetime->packets.rekey); | |
979 | sa->lft.hard_packet_limit = XFRM_LIMIT(lifetime->packets.life); | |
507f26f6 | 980 | /* we use lifetimes since added, not since used */ |
e75f4237 TB |
981 | sa->lft.soft_add_expires_seconds = lifetime->time.rekey; |
982 | sa->lft.hard_add_expires_seconds = lifetime->time.life; | |
507f26f6 TB |
983 | sa->lft.soft_use_expires_seconds = 0; |
984 | sa->lft.hard_use_expires_seconds = 0; | |
7daf5226 | 985 | |
507f26f6 | 986 | struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_info); |
7daf5226 | 987 | |
507f26f6 TB |
988 | switch (enc_alg) |
989 | { | |
990 | case ENCR_UNDEFINED: | |
991 | /* no encryption */ | |
992 | break; | |
507f26f6 | 993 | case ENCR_AES_CCM_ICV16: |
507f26f6 | 994 | case ENCR_AES_GCM_ICV16: |
8ddcac4c | 995 | case ENCR_CAMELLIA_CCM_ICV16: |
e517b4b1 MW |
996 | icv_size += 32; |
997 | /* FALL */ | |
998 | case ENCR_AES_CCM_ICV12: | |
999 | case ENCR_AES_GCM_ICV12: | |
8ddcac4c | 1000 | case ENCR_CAMELLIA_CCM_ICV12: |
e517b4b1 MW |
1001 | icv_size += 32; |
1002 | /* FALL */ | |
1003 | case ENCR_AES_CCM_ICV8: | |
1004 | case ENCR_AES_GCM_ICV8: | |
8ddcac4c | 1005 | case ENCR_CAMELLIA_CCM_ICV8: |
507f26f6 | 1006 | { |
c5ebd005 AS |
1007 | struct xfrm_algo_aead *algo; |
1008 | ||
e517b4b1 | 1009 | alg_name = lookup_algorithm(encryption_algs, enc_alg); |
507f26f6 TB |
1010 | if (alg_name == NULL) |
1011 | { | |
1012 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", | |
1013 | encryption_algorithm_names, enc_alg); | |
1014 | return FAILED; | |
1015 | } | |
1016 | DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", | |
e517b4b1 | 1017 | encryption_algorithm_names, enc_alg, enc_key.len * 8); |
7daf5226 | 1018 | |
c5ebd005 | 1019 | rthdr->rta_type = XFRMA_ALG_AEAD; |
e517b4b1 | 1020 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_key.len); |
507f26f6 TB |
1021 | hdr->nlmsg_len += rthdr->rta_len; |
1022 | if (hdr->nlmsg_len > sizeof(request)) | |
1023 | { | |
1024 | return FAILED; | |
1025 | } | |
7daf5226 | 1026 | |
c5ebd005 | 1027 | algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr); |
e517b4b1 | 1028 | algo->alg_key_len = enc_key.len * 8; |
507f26f6 TB |
1029 | algo->alg_icv_len = icv_size; |
1030 | strcpy(algo->alg_name, alg_name); | |
e517b4b1 | 1031 | memcpy(algo->alg_key, enc_key.ptr, enc_key.len); |
7daf5226 | 1032 | |
507f26f6 TB |
1033 | rthdr = XFRM_RTA_NEXT(rthdr); |
1034 | break; | |
1035 | } | |
1036 | default: | |
1037 | { | |
c5ebd005 AS |
1038 | struct xfrm_algo *algo; |
1039 | ||
e517b4b1 | 1040 | alg_name = lookup_algorithm(encryption_algs, enc_alg); |
507f26f6 TB |
1041 | if (alg_name == NULL) |
1042 | { | |
1043 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", | |
1044 | encryption_algorithm_names, enc_alg); | |
1045 | return FAILED; | |
1046 | } | |
1047 | DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", | |
e517b4b1 | 1048 | encryption_algorithm_names, enc_alg, enc_key.len * 8); |
7daf5226 | 1049 | |
c5ebd005 | 1050 | rthdr->rta_type = XFRMA_ALG_CRYPT; |
e517b4b1 | 1051 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len); |
507f26f6 TB |
1052 | hdr->nlmsg_len += rthdr->rta_len; |
1053 | if (hdr->nlmsg_len > sizeof(request)) | |
1054 | { | |
1055 | return FAILED; | |
1056 | } | |
7daf5226 | 1057 | |
c5ebd005 | 1058 | algo = (struct xfrm_algo*)RTA_DATA(rthdr); |
e517b4b1 | 1059 | algo->alg_key_len = enc_key.len * 8; |
507f26f6 | 1060 | strcpy(algo->alg_name, alg_name); |
e517b4b1 | 1061 | memcpy(algo->alg_key, enc_key.ptr, enc_key.len); |
7daf5226 | 1062 | |
507f26f6 | 1063 | rthdr = XFRM_RTA_NEXT(rthdr); |
507f26f6 TB |
1064 | } |
1065 | } | |
7daf5226 | 1066 | |
eebfa73f MW |
1067 | if (int_alg == AUTH_HMAC_SHA2_256_128) |
1068 | { | |
1069 | /* the kernel uses SHA256 with 96 bit truncation by default, | |
1070 | * use specified truncation size supported by newer kernels */ | |
1071 | rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC; | |
1072 | alg_name = "hmac(sha256)"; | |
1073 | DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", | |
1074 | integrity_algorithm_names, int_alg, int_key.len * 8); | |
1075 | ||
1076 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) + int_key.len); | |
1077 | hdr->nlmsg_len += rthdr->rta_len; | |
1078 | if (hdr->nlmsg_len > sizeof(request)) | |
1079 | { | |
1080 | return FAILED; | |
1081 | } | |
1082 | ||
1083 | struct xfrm_algo_auth* algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr); | |
1084 | algo->alg_key_len = int_key.len * 8; | |
1085 | algo->alg_trunc_len = 128; | |
1086 | strcpy(algo->alg_name, alg_name); | |
1087 | memcpy(algo->alg_key, int_key.ptr, int_key.len); | |
1088 | ||
1089 | rthdr = XFRM_RTA_NEXT(rthdr); | |
1090 | } | |
1091 | else if (int_alg != AUTH_UNDEFINED) | |
507f26f6 TB |
1092 | { |
1093 | rthdr->rta_type = XFRMA_ALG_AUTH; | |
e517b4b1 | 1094 | alg_name = lookup_algorithm(integrity_algs, int_alg); |
507f26f6 TB |
1095 | if (alg_name == NULL) |
1096 | { | |
7daf5226 | 1097 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", |
507f26f6 TB |
1098 | integrity_algorithm_names, int_alg); |
1099 | return FAILED; | |
1100 | } | |
1101 | DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", | |
e517b4b1 | 1102 | integrity_algorithm_names, int_alg, int_key.len * 8); |
7daf5226 | 1103 | |
e517b4b1 | 1104 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len); |
507f26f6 TB |
1105 | hdr->nlmsg_len += rthdr->rta_len; |
1106 | if (hdr->nlmsg_len > sizeof(request)) | |
1107 | { | |
1108 | return FAILED; | |
1109 | } | |
7daf5226 | 1110 | |
507f26f6 | 1111 | struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); |
e517b4b1 | 1112 | algo->alg_key_len = int_key.len * 8; |
507f26f6 | 1113 | strcpy(algo->alg_name, alg_name); |
e517b4b1 | 1114 | memcpy(algo->alg_key, int_key.ptr, int_key.len); |
7daf5226 | 1115 | |
507f26f6 TB |
1116 | rthdr = XFRM_RTA_NEXT(rthdr); |
1117 | } | |
7daf5226 | 1118 | |
507f26f6 TB |
1119 | if (ipcomp != IPCOMP_NONE) |
1120 | { | |
1121 | rthdr->rta_type = XFRMA_ALG_COMP; | |
e517b4b1 | 1122 | alg_name = lookup_algorithm(compression_algs, ipcomp); |
507f26f6 TB |
1123 | if (alg_name == NULL) |
1124 | { | |
7daf5226 | 1125 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", |
507f26f6 TB |
1126 | ipcomp_transform_names, ipcomp); |
1127 | return FAILED; | |
1128 | } | |
1129 | DBG2(DBG_KNL, " using compression algorithm %N", | |
1130 | ipcomp_transform_names, ipcomp); | |
7daf5226 | 1131 | |
507f26f6 TB |
1132 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo)); |
1133 | hdr->nlmsg_len += rthdr->rta_len; | |
1134 | if (hdr->nlmsg_len > sizeof(request)) | |
1135 | { | |
1136 | return FAILED; | |
1137 | } | |
7daf5226 | 1138 | |
507f26f6 TB |
1139 | struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); |
1140 | algo->alg_key_len = 0; | |
1141 | strcpy(algo->alg_name, alg_name); | |
7daf5226 | 1142 | |
507f26f6 TB |
1143 | rthdr = XFRM_RTA_NEXT(rthdr); |
1144 | } | |
7daf5226 | 1145 | |
507f26f6 TB |
1146 | if (encap) |
1147 | { | |
1148 | rthdr->rta_type = XFRMA_ENCAP; | |
1149 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); | |
1150 | ||
1151 | hdr->nlmsg_len += rthdr->rta_len; | |
1152 | if (hdr->nlmsg_len > sizeof(request)) | |
1153 | { | |
1154 | return FAILED; | |
1155 | } | |
1156 | ||
1157 | struct xfrm_encap_tmpl* tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); | |
1158 | tmpl->encap_type = UDP_ENCAP_ESPINUDP; | |
1159 | tmpl->encap_sport = htons(src->get_port(src)); | |
1160 | tmpl->encap_dport = htons(dst->get_port(dst)); | |
1161 | memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); | |
7daf5226 MW |
1162 | /* encap_oa could probably be derived from the |
1163 | * traffic selectors [rfc4306, p39]. In the netlink kernel implementation | |
1164 | * pluto does the same as we do here but it uses encap_oa in the | |
1165 | * pfkey implementation. BUT as /usr/src/linux/net/key/af_key.c indicates | |
507f26f6 TB |
1166 | * the kernel ignores it anyway |
1167 | * -> does that mean that NAT-T encap doesn't work in transport mode? | |
7daf5226 | 1168 | * No. The reason the kernel ignores NAT-OA is that it recomputes |
507f26f6 TB |
1169 | * (or, rather, just ignores) the checksum. If packets pass |
1170 | * the IPsec checks it marks them "checksum ok" so OA isn't needed. */ | |
1171 | rthdr = XFRM_RTA_NEXT(rthdr); | |
1172 | } | |
abc177e0 | 1173 | |
507f26f6 TB |
1174 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) |
1175 | { | |
1176 | DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi)); | |
1177 | return FAILED; | |
1178 | } | |
1179 | return SUCCESS; | |
1180 | } | |
1181 | ||
1182 | /** | |
1183 | * Get the replay state (i.e. sequence numbers) of an SA. | |
1184 | */ | |
1185 | static status_t get_replay_state(private_kernel_netlink_ipsec_t *this, | |
1186 | u_int32_t spi, protocol_id_t protocol, host_t *dst, | |
1187 | struct xfrm_replay_state *replay) | |
1188 | { | |
21bf86f7 | 1189 | netlink_buf_t request; |
507f26f6 TB |
1190 | struct nlmsghdr *hdr, *out = NULL; |
1191 | struct xfrm_aevent_id *out_aevent = NULL, *aevent_id; | |
1192 | size_t len; | |
1193 | struct rtattr *rta; | |
1194 | size_t rtasize; | |
7daf5226 | 1195 | |
507f26f6 | 1196 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1197 | |
507f26f6 TB |
1198 | DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x", ntohl(spi)); |
1199 | ||
1200 | hdr = (struct nlmsghdr*)request; | |
1201 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
1202 | hdr->nlmsg_type = XFRM_MSG_GETAE; | |
1203 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | |
7daf5226 | 1204 | |
507f26f6 TB |
1205 | aevent_id = (struct xfrm_aevent_id*)NLMSG_DATA(hdr); |
1206 | aevent_id->flags = XFRM_AE_RVAL; | |
7daf5226 | 1207 | |
507f26f6 TB |
1208 | host2xfrm(dst, &aevent_id->sa_id.daddr); |
1209 | aevent_id->sa_id.spi = spi; | |
1210 | aevent_id->sa_id.proto = proto_ike2kernel(protocol); | |
1211 | aevent_id->sa_id.family = dst->get_family(dst); | |
7daf5226 | 1212 | |
507f26f6 TB |
1213 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) |
1214 | { | |
1215 | hdr = out; | |
1216 | while (NLMSG_OK(hdr, len)) | |
1217 | { | |
1218 | switch (hdr->nlmsg_type) | |
1219 | { | |
1220 | case XFRM_MSG_NEWAE: | |
1221 | { | |
1222 | out_aevent = NLMSG_DATA(hdr); | |
1223 | break; | |
1224 | } | |
1225 | case NLMSG_ERROR: | |
1226 | { | |
1227 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
1228 | DBG1(DBG_KNL, "querying replay state from SAD entry failed: %s (%d)", | |
1229 | strerror(-err->error), -err->error); | |
1230 | break; | |
1231 | } | |
1232 | default: | |
1233 | hdr = NLMSG_NEXT(hdr, len); | |
1234 | continue; | |
1235 | case NLMSG_DONE: | |
1236 | break; | |
1237 | } | |
1238 | break; | |
1239 | } | |
1240 | } | |
7daf5226 | 1241 | |
507f26f6 TB |
1242 | if (out_aevent == NULL) |
1243 | { | |
1244 | DBG1(DBG_KNL, "unable to query replay state from SAD entry with SPI %.8x", | |
1245 | ntohl(spi)); | |
1246 | free(out); | |
1247 | return FAILED; | |
1248 | } | |
7daf5226 | 1249 | |
507f26f6 TB |
1250 | rta = XFRM_RTA(out, struct xfrm_aevent_id); |
1251 | rtasize = XFRM_PAYLOAD(out, struct xfrm_aevent_id); | |
1252 | while(RTA_OK(rta, rtasize)) | |
1253 | { | |
a65e1c5c MW |
1254 | if (rta->rta_type == XFRMA_REPLAY_VAL && |
1255 | RTA_PAYLOAD(rta) == sizeof(struct xfrm_replay_state)) | |
507f26f6 | 1256 | { |
a65e1c5c | 1257 | memcpy(replay, RTA_DATA(rta), RTA_PAYLOAD(rta)); |
507f26f6 TB |
1258 | free(out); |
1259 | return SUCCESS; | |
1260 | } | |
1261 | rta = RTA_NEXT(rta, rtasize); | |
1262 | } | |
7daf5226 | 1263 | |
507f26f6 TB |
1264 | DBG1(DBG_KNL, "unable to query replay state from SAD entry with SPI %.8x", |
1265 | ntohl(spi)); | |
1266 | free(out); | |
1267 | return FAILED; | |
1268 | } | |
1269 | ||
2ad51539 AS |
1270 | /** |
1271 | * Implementation of kernel_interface_t.query_sa. | |
1272 | */ | |
1273 | static status_t query_sa(private_kernel_netlink_ipsec_t *this, host_t *src, | |
1274 | host_t *dst, u_int32_t spi, protocol_id_t protocol, | |
1275 | u_int64_t *bytes) | |
1276 | { | |
1277 | netlink_buf_t request; | |
1278 | struct nlmsghdr *out = NULL, *hdr; | |
1279 | struct xfrm_usersa_id *sa_id; | |
1280 | struct xfrm_usersa_info *sa = NULL; | |
1281 | size_t len; | |
7daf5226 | 1282 | |
2ad51539 AS |
1283 | memset(&request, 0, sizeof(request)); |
1284 | ||
1285 | DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi)); | |
1286 | ||
1287 | hdr = (struct nlmsghdr*)request; | |
1288 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
1289 | hdr->nlmsg_type = XFRM_MSG_GETSA; | |
1290 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); | |
1291 | ||
1292 | sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); | |
1293 | host2xfrm(dst, &sa_id->daddr); | |
1294 | sa_id->spi = spi; | |
1295 | sa_id->proto = proto_ike2kernel(protocol); | |
1296 | sa_id->family = dst->get_family(dst); | |
7daf5226 | 1297 | |
2ad51539 AS |
1298 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) |
1299 | { | |
1300 | hdr = out; | |
1301 | while (NLMSG_OK(hdr, len)) | |
1302 | { | |
1303 | switch (hdr->nlmsg_type) | |
1304 | { | |
1305 | case XFRM_MSG_NEWSA: | |
1306 | { | |
1307 | sa = (struct xfrm_usersa_info*)NLMSG_DATA(hdr); | |
1308 | break; | |
1309 | } | |
1310 | case NLMSG_ERROR: | |
1311 | { | |
1312 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
1313 | DBG1(DBG_KNL, "querying SAD entry with SPI %.8x failed: %s (%d)", | |
1314 | ntohl(spi), strerror(-err->error), -err->error); | |
1315 | break; | |
1316 | } | |
1317 | default: | |
1318 | hdr = NLMSG_NEXT(hdr, len); | |
1319 | continue; | |
1320 | case NLMSG_DONE: | |
1321 | break; | |
1322 | } | |
1323 | break; | |
1324 | } | |
1325 | } | |
7daf5226 | 1326 | |
2ad51539 AS |
1327 | if (sa == NULL) |
1328 | { | |
1329 | DBG2(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi)); | |
1330 | free(out); | |
1331 | return FAILED; | |
1332 | } | |
1333 | *bytes = sa->curlft.bytes; | |
7daf5226 | 1334 | |
2ad51539 AS |
1335 | free(out); |
1336 | return SUCCESS; | |
1337 | } | |
f5812086 MW |
1338 | /** |
1339 | * Implementation of kernel_interface_t.del_sa. | |
1340 | */ | |
d24a74c5 TB |
1341 | static status_t del_sa(private_kernel_netlink_ipsec_t *this, host_t *src, |
1342 | host_t *dst, u_int32_t spi, protocol_id_t protocol, | |
1343 | u_int16_t cpi) | |
f5812086 | 1344 | { |
21bf86f7 | 1345 | netlink_buf_t request; |
f5812086 MW |
1346 | struct nlmsghdr *hdr; |
1347 | struct xfrm_usersa_id *sa_id; | |
7daf5226 | 1348 | |
f5812086 MW |
1349 | /* if IPComp was used, we first delete the additional IPComp SA */ |
1350 | if (cpi) | |
1351 | { | |
d24a74c5 | 1352 | del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0); |
f5812086 | 1353 | } |
7daf5226 | 1354 | |
f5812086 | 1355 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1356 | |
f5812086 | 1357 | DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi)); |
7daf5226 | 1358 | |
f5812086 MW |
1359 | hdr = (struct nlmsghdr*)request; |
1360 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
1361 | hdr->nlmsg_type = XFRM_MSG_DELSA; | |
1362 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); | |
7daf5226 | 1363 | |
f5812086 MW |
1364 | sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); |
1365 | host2xfrm(dst, &sa_id->daddr); | |
1366 | sa_id->spi = spi; | |
1367 | sa_id->proto = proto_ike2kernel(protocol); | |
1368 | sa_id->family = dst->get_family(dst); | |
7daf5226 | 1369 | |
f5812086 MW |
1370 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) |
1371 | { | |
1372 | DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi)); | |
1373 | return FAILED; | |
1374 | } | |
1375 | DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi)); | |
1376 | return SUCCESS; | |
1377 | } | |
1378 | ||
507f26f6 TB |
1379 | /** |
1380 | * Implementation of kernel_interface_t.update_sa. | |
1381 | */ | |
1382 | static status_t update_sa(private_kernel_netlink_ipsec_t *this, | |
ea625fab | 1383 | u_int32_t spi, protocol_id_t protocol, u_int16_t cpi, |
507f26f6 | 1384 | host_t *src, host_t *dst, |
ea625fab | 1385 | host_t *new_src, host_t *new_dst, |
fd2ebf0c | 1386 | bool old_encap, bool new_encap) |
507f26f6 | 1387 | { |
21bf86f7 MW |
1388 | netlink_buf_t request; |
1389 | u_char *pos; | |
507f26f6 TB |
1390 | struct nlmsghdr *hdr, *out = NULL; |
1391 | struct xfrm_usersa_id *sa_id; | |
1392 | struct xfrm_usersa_info *out_sa = NULL, *sa; | |
1393 | size_t len; | |
1394 | struct rtattr *rta; | |
1395 | size_t rtasize; | |
1396 | struct xfrm_encap_tmpl* tmpl = NULL; | |
f5812086 | 1397 | bool got_replay_state = FALSE; |
507f26f6 | 1398 | struct xfrm_replay_state replay; |
7daf5226 | 1399 | |
ea625fab TB |
1400 | /* if IPComp is used, we first update the IPComp SA */ |
1401 | if (cpi) | |
1402 | { | |
f5812086 MW |
1403 | update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0, |
1404 | src, dst, new_src, new_dst, FALSE, FALSE); | |
ea625fab | 1405 | } |
7daf5226 | 1406 | |
507f26f6 | 1407 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1408 | |
507f26f6 | 1409 | DBG2(DBG_KNL, "querying SAD entry with SPI %.8x for update", ntohl(spi)); |
7daf5226 | 1410 | |
507f26f6 TB |
1411 | /* query the existing SA first */ |
1412 | hdr = (struct nlmsghdr*)request; | |
1413 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
1414 | hdr->nlmsg_type = XFRM_MSG_GETSA; | |
1415 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); | |
7daf5226 | 1416 | |
507f26f6 TB |
1417 | sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); |
1418 | host2xfrm(dst, &sa_id->daddr); | |
1419 | sa_id->spi = spi; | |
1420 | sa_id->proto = proto_ike2kernel(protocol); | |
1421 | sa_id->family = dst->get_family(dst); | |
7daf5226 | 1422 | |
507f26f6 TB |
1423 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) |
1424 | { | |
1425 | hdr = out; | |
1426 | while (NLMSG_OK(hdr, len)) | |
1427 | { | |
1428 | switch (hdr->nlmsg_type) | |
1429 | { | |
1430 | case XFRM_MSG_NEWSA: | |
1431 | { | |
1432 | out_sa = NLMSG_DATA(hdr); | |
1433 | break; | |
1434 | } | |
1435 | case NLMSG_ERROR: | |
1436 | { | |
1437 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
1438 | DBG1(DBG_KNL, "querying SAD entry failed: %s (%d)", | |
1439 | strerror(-err->error), -err->error); | |
1440 | break; | |
1441 | } | |
1442 | default: | |
1443 | hdr = NLMSG_NEXT(hdr, len); | |
1444 | continue; | |
1445 | case NLMSG_DONE: | |
1446 | break; | |
1447 | } | |
1448 | break; | |
1449 | } | |
1450 | } | |
1451 | if (out_sa == NULL) | |
1452 | { | |
1453 | DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi)); | |
1454 | free(out); | |
1455 | return FAILED; | |
1456 | } | |
7daf5226 | 1457 | |
507f26f6 | 1458 | /* try to get the replay state */ |
f5812086 MW |
1459 | if (get_replay_state(this, spi, protocol, dst, &replay) == SUCCESS) |
1460 | { | |
1461 | got_replay_state = TRUE; | |
1462 | } | |
7daf5226 | 1463 | |
ea625fab | 1464 | /* delete the old SA (without affecting the IPComp SA) */ |
d24a74c5 | 1465 | if (del_sa(this, src, dst, spi, protocol, 0) != SUCCESS) |
507f26f6 TB |
1466 | { |
1467 | DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", ntohl(spi)); | |
1468 | free(out); | |
1469 | return FAILED; | |
1470 | } | |
7daf5226 | 1471 | |
507f26f6 TB |
1472 | DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", |
1473 | ntohl(spi), src, dst, new_src, new_dst); | |
507f26f6 TB |
1474 | /* copy over the SA from out to request */ |
1475 | hdr = (struct nlmsghdr*)request; | |
1476 | memcpy(hdr, out, min(out->nlmsg_len, sizeof(request))); | |
7daf5226 | 1477 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; |
507f26f6 TB |
1478 | hdr->nlmsg_type = XFRM_MSG_NEWSA; |
1479 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); | |
1480 | sa = NLMSG_DATA(hdr); | |
1481 | sa->family = new_dst->get_family(new_dst); | |
7daf5226 | 1482 | |
507f26f6 TB |
1483 | if (!src->ip_equals(src, new_src)) |
1484 | { | |
1485 | host2xfrm(new_src, &sa->saddr); | |
1486 | } | |
1487 | if (!dst->ip_equals(dst, new_dst)) | |
1488 | { | |
1489 | host2xfrm(new_dst, &sa->id.daddr); | |
1490 | } | |
7daf5226 | 1491 | |
507f26f6 TB |
1492 | rta = XFRM_RTA(out, struct xfrm_usersa_info); |
1493 | rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info); | |
1494 | pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info); | |
1495 | while(RTA_OK(rta, rtasize)) | |
1496 | { | |
1497 | /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ | |
fd2ebf0c | 1498 | if (rta->rta_type != XFRMA_ENCAP || new_encap) |
507f26f6 TB |
1499 | { |
1500 | if (rta->rta_type == XFRMA_ENCAP) | |
1501 | { /* update encap tmpl */ | |
1502 | tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); | |
1503 | tmpl->encap_sport = ntohs(new_src->get_port(new_src)); | |
1504 | tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); | |
7daf5226 | 1505 | } |
507f26f6 TB |
1506 | memcpy(pos, rta, rta->rta_len); |
1507 | pos += RTA_ALIGN(rta->rta_len); | |
1508 | hdr->nlmsg_len += RTA_ALIGN(rta->rta_len); | |
1509 | } | |
1510 | rta = RTA_NEXT(rta, rtasize); | |
1511 | } | |
7daf5226 | 1512 | |
507f26f6 | 1513 | rta = (struct rtattr*)pos; |
fd2ebf0c | 1514 | if (tmpl == NULL && new_encap) |
507f26f6 TB |
1515 | { /* add tmpl if we are enabling it */ |
1516 | rta->rta_type = XFRMA_ENCAP; | |
1517 | rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); | |
7daf5226 | 1518 | |
507f26f6 TB |
1519 | hdr->nlmsg_len += rta->rta_len; |
1520 | if (hdr->nlmsg_len > sizeof(request)) | |
1521 | { | |
1522 | return FAILED; | |
1523 | } | |
7daf5226 | 1524 | |
507f26f6 TB |
1525 | tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); |
1526 | tmpl->encap_type = UDP_ENCAP_ESPINUDP; | |
1527 | tmpl->encap_sport = ntohs(new_src->get_port(new_src)); | |
1528 | tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); | |
1529 | memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); | |
7daf5226 | 1530 | |
507f26f6 TB |
1531 | rta = XFRM_RTA_NEXT(rta); |
1532 | } | |
7daf5226 | 1533 | |
507f26f6 TB |
1534 | if (got_replay_state) |
1535 | { /* copy the replay data if available */ | |
1536 | rta->rta_type = XFRMA_REPLAY_VAL; | |
1537 | rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state)); | |
7daf5226 | 1538 | |
507f26f6 TB |
1539 | hdr->nlmsg_len += rta->rta_len; |
1540 | if (hdr->nlmsg_len > sizeof(request)) | |
1541 | { | |
1542 | return FAILED; | |
1543 | } | |
1544 | memcpy(RTA_DATA(rta), &replay, sizeof(replay)); | |
7daf5226 | 1545 | |
507f26f6 TB |
1546 | rta = XFRM_RTA_NEXT(rta); |
1547 | } | |
abc177e0 | 1548 | |
507f26f6 TB |
1549 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) |
1550 | { | |
1551 | DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi)); | |
1552 | free(out); | |
1553 | return FAILED; | |
1554 | } | |
1555 | free(out); | |
7daf5226 | 1556 | |
507f26f6 TB |
1557 | return SUCCESS; |
1558 | } | |
1559 | ||
507f26f6 TB |
1560 | /** |
1561 | * Implementation of kernel_interface_t.add_policy. | |
1562 | */ | |
7daf5226 | 1563 | static status_t add_policy(private_kernel_netlink_ipsec_t *this, |
507f26f6 TB |
1564 | host_t *src, host_t *dst, |
1565 | traffic_selector_t *src_ts, | |
1566 | traffic_selector_t *dst_ts, | |
ea625fab TB |
1567 | policy_dir_t direction, u_int32_t spi, |
1568 | protocol_id_t protocol, u_int32_t reqid, | |
1569 | ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, | |
1570 | bool routed) | |
507f26f6 | 1571 | { |
507f26f6 TB |
1572 | policy_entry_t *current, *policy; |
1573 | bool found = FALSE; | |
21bf86f7 | 1574 | netlink_buf_t request; |
507f26f6 TB |
1575 | struct xfrm_userpolicy_info *policy_info; |
1576 | struct nlmsghdr *hdr; | |
7daf5226 | 1577 | |
507f26f6 TB |
1578 | /* create a policy */ |
1579 | policy = malloc_thing(policy_entry_t); | |
1580 | memset(policy, 0, sizeof(policy_entry_t)); | |
1581 | policy->sel = ts2selector(src_ts, dst_ts); | |
1582 | policy->direction = direction; | |
7daf5226 | 1583 | |
507f26f6 | 1584 | /* find the policy, which matches EXACTLY */ |
3ac5a0db | 1585 | this->mutex->lock(this->mutex); |
3fb404d8 TB |
1586 | current = this->policies->get(this->policies, policy); |
1587 | if (current) | |
507f26f6 | 1588 | { |
3fb404d8 TB |
1589 | /* use existing policy */ |
1590 | current->refcount++; | |
1591 | DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " | |
1592 | "refcount", src_ts, dst_ts, | |
1593 | policy_dir_names, direction); | |
1594 | free(policy); | |
1595 | policy = current; | |
1596 | found = TRUE; | |
507f26f6 | 1597 | } |
3fb404d8 | 1598 | else |
507f26f6 | 1599 | { /* apply the new one, if we have no such policy */ |
3fb404d8 | 1600 | this->policies->put(this->policies, policy, policy); |
507f26f6 TB |
1601 | policy->refcount = 1; |
1602 | } | |
7daf5226 | 1603 | |
507f26f6 TB |
1604 | DBG2(DBG_KNL, "adding policy %R === %R %N", src_ts, dst_ts, |
1605 | policy_dir_names, direction); | |
7daf5226 | 1606 | |
507f26f6 TB |
1607 | memset(&request, 0, sizeof(request)); |
1608 | hdr = (struct nlmsghdr*)request; | |
1609 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
1610 | hdr->nlmsg_type = found ? XFRM_MSG_UPDPOLICY : XFRM_MSG_NEWPOLICY; | |
1611 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)); | |
1612 | ||
1613 | policy_info = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr); | |
1614 | policy_info->sel = policy->sel; | |
1615 | policy_info->dir = policy->direction; | |
1616 | /* calculate priority based on source selector size, small size = high prio */ | |
ea625fab | 1617 | policy_info->priority = routed ? PRIO_LOW : PRIO_HIGH; |
507f26f6 TB |
1618 | policy_info->priority -= policy->sel.prefixlen_s * 10; |
1619 | policy_info->priority -= policy->sel.proto ? 2 : 0; | |
1620 | policy_info->priority -= policy->sel.sport_mask ? 1 : 0; | |
1621 | policy_info->action = XFRM_POLICY_ALLOW; | |
1622 | policy_info->share = XFRM_SHARE_ANY; | |
3ac5a0db | 1623 | this->mutex->unlock(this->mutex); |
7daf5226 | 1624 | |
507f26f6 TB |
1625 | /* policies don't expire */ |
1626 | policy_info->lft.soft_byte_limit = XFRM_INF; | |
1627 | policy_info->lft.soft_packet_limit = XFRM_INF; | |
1628 | policy_info->lft.hard_byte_limit = XFRM_INF; | |
1629 | policy_info->lft.hard_packet_limit = XFRM_INF; | |
1630 | policy_info->lft.soft_add_expires_seconds = 0; | |
1631 | policy_info->lft.hard_add_expires_seconds = 0; | |
1632 | policy_info->lft.soft_use_expires_seconds = 0; | |
1633 | policy_info->lft.hard_use_expires_seconds = 0; | |
7daf5226 | 1634 | |
507f26f6 TB |
1635 | struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info); |
1636 | rthdr->rta_type = XFRMA_TMPL; | |
1637 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); | |
7daf5226 | 1638 | |
507f26f6 TB |
1639 | hdr->nlmsg_len += rthdr->rta_len; |
1640 | if (hdr->nlmsg_len > sizeof(request)) | |
1641 | { | |
1642 | return FAILED; | |
1643 | } | |
7daf5226 | 1644 | |
507f26f6 | 1645 | struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr); |
7daf5226 | 1646 | |
507f26f6 TB |
1647 | if (ipcomp != IPCOMP_NONE) |
1648 | { | |
1649 | tmpl->reqid = reqid; | |
1650 | tmpl->id.proto = IPPROTO_COMP; | |
1651 | tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; | |
d24a74c5 | 1652 | tmpl->mode = mode2kernel(mode); |
507f26f6 TB |
1653 | tmpl->optional = direction != POLICY_OUT; |
1654 | tmpl->family = src->get_family(src); | |
7daf5226 | 1655 | |
507f26f6 TB |
1656 | host2xfrm(src, &tmpl->saddr); |
1657 | host2xfrm(dst, &tmpl->id.daddr); | |
7daf5226 | 1658 | |
507f26f6 TB |
1659 | /* add an additional xfrm_user_tmpl */ |
1660 | rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); | |
1661 | hdr->nlmsg_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); | |
1662 | if (hdr->nlmsg_len > sizeof(request)) | |
1663 | { | |
1664 | return FAILED; | |
1665 | } | |
7daf5226 | 1666 | |
507f26f6 | 1667 | tmpl++; |
2b2c69e9 MW |
1668 | |
1669 | /* use transport mode for ESP if we have a tunnel mode IPcomp SA */ | |
1670 | mode = MODE_TRANSPORT; | |
1671 | } | |
1672 | else | |
1673 | { | |
1674 | /* when using IPcomp, only the IPcomp SA uses tmp src/dst addresses */ | |
1675 | host2xfrm(src, &tmpl->saddr); | |
1676 | host2xfrm(dst, &tmpl->id.daddr); | |
507f26f6 | 1677 | } |
7daf5226 | 1678 | |
507f26f6 TB |
1679 | tmpl->reqid = reqid; |
1680 | tmpl->id.proto = proto_ike2kernel(protocol); | |
1681 | tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; | |
d24a74c5 | 1682 | tmpl->mode = mode2kernel(mode); |
507f26f6 | 1683 | tmpl->family = src->get_family(src); |
7daf5226 | 1684 | |
507f26f6 TB |
1685 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) |
1686 | { | |
1687 | DBG1(DBG_KNL, "unable to add policy %R === %R %N", src_ts, dst_ts, | |
1688 | policy_dir_names, direction); | |
1689 | return FAILED; | |
1690 | } | |
7daf5226 | 1691 | |
507f26f6 TB |
1692 | /* install a route, if: |
1693 | * - we are NOT updating a policy | |
1694 | * - this is a forward policy (to just get one for each child) | |
1695 | * - we are in tunnel mode | |
507f26f6 TB |
1696 | * - routing is not disabled via strongswan.conf |
1697 | */ | |
1698 | if (policy->route == NULL && direction == POLICY_FWD && | |
5be75c2c | 1699 | mode != MODE_TRANSPORT && this->install_routes) |
507f26f6 TB |
1700 | { |
1701 | route_entry_t *route = malloc_thing(route_entry_t); | |
7daf5226 | 1702 | |
1adaa02b TB |
1703 | if (charon->kernel_interface->get_address_by_ts(charon->kernel_interface, |
1704 | dst_ts, &route->src_ip) == SUCCESS) | |
507f26f6 | 1705 | { |
5be75c2c MW |
1706 | if (policy->sel.family == AF_INET) |
1707 | { | |
1708 | /* get the nexthop to src (src as we are in POLICY_FWD).*/ | |
1709 | route->gateway = charon->kernel_interface->get_nexthop( | |
507f26f6 | 1710 | charon->kernel_interface, src); |
5be75c2c MW |
1711 | /* for IPv4, the route is installed on the outgoing interface */ |
1712 | route->if_name = charon->kernel_interface->get_interface( | |
1713 | charon->kernel_interface, dst); | |
1714 | route->dst_net = chunk_alloc(4); | |
1715 | } | |
1716 | else | |
1717 | { | |
1718 | route->gateway = NULL; | |
1719 | /* for IPv6, it is on the interface with our source address */ | |
1720 | route->if_name = charon->kernel_interface->get_interface( | |
1721 | charon->kernel_interface, route->src_ip); | |
1722 | route->dst_net = chunk_alloc(16); | |
1723 | } | |
507f26f6 TB |
1724 | memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len); |
1725 | route->prefixlen = policy->sel.prefixlen_s; | |
7daf5226 | 1726 | |
31537fd9 | 1727 | if (route->if_name) |
7daf5226 | 1728 | { |
31537fd9 MW |
1729 | switch (charon->kernel_interface->add_route( |
1730 | charon->kernel_interface, route->dst_net, | |
1731 | route->prefixlen, route->gateway, | |
1732 | route->src_ip, route->if_name)) | |
1733 | { | |
1734 | default: | |
1735 | DBG1(DBG_KNL, "unable to install source route for %H", | |
1736 | route->src_ip); | |
1737 | /* FALL */ | |
1738 | case ALREADY_DONE: | |
1739 | /* route exists, do not uninstall */ | |
1740 | route_entry_destroy(route); | |
1741 | break; | |
1742 | case SUCCESS: | |
1743 | /* cache the installed route */ | |
1744 | policy->route = route; | |
1745 | break; | |
1746 | } | |
1747 | } | |
1748 | else | |
507f26f6 | 1749 | { |
31537fd9 | 1750 | route_entry_destroy(route); |
507f26f6 TB |
1751 | } |
1752 | } | |
1753 | else | |
1754 | { | |
1755 | free(route); | |
1756 | } | |
1757 | } | |
507f26f6 TB |
1758 | return SUCCESS; |
1759 | } | |
1760 | ||
1761 | /** | |
1762 | * Implementation of kernel_interface_t.query_policy. | |
1763 | */ | |
1764 | static status_t query_policy(private_kernel_netlink_ipsec_t *this, | |
7daf5226 | 1765 | traffic_selector_t *src_ts, |
507f26f6 TB |
1766 | traffic_selector_t *dst_ts, |
1767 | policy_dir_t direction, u_int32_t *use_time) | |
1768 | { | |
21bf86f7 | 1769 | netlink_buf_t request; |
507f26f6 TB |
1770 | struct nlmsghdr *out = NULL, *hdr; |
1771 | struct xfrm_userpolicy_id *policy_id; | |
1772 | struct xfrm_userpolicy_info *policy = NULL; | |
1773 | size_t len; | |
7daf5226 | 1774 | |
507f26f6 | 1775 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1776 | |
507f26f6 TB |
1777 | DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts, |
1778 | policy_dir_names, direction); | |
1779 | ||
1780 | hdr = (struct nlmsghdr*)request; | |
1781 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
1782 | hdr->nlmsg_type = XFRM_MSG_GETPOLICY; | |
1783 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)); | |
1784 | ||
1785 | policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr); | |
1786 | policy_id->sel = ts2selector(src_ts, dst_ts); | |
1787 | policy_id->dir = direction; | |
7daf5226 | 1788 | |
507f26f6 TB |
1789 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) |
1790 | { | |
1791 | hdr = out; | |
1792 | while (NLMSG_OK(hdr, len)) | |
1793 | { | |
1794 | switch (hdr->nlmsg_type) | |
1795 | { | |
1796 | case XFRM_MSG_NEWPOLICY: | |
1797 | { | |
1798 | policy = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr); | |
1799 | break; | |
1800 | } | |
1801 | case NLMSG_ERROR: | |
1802 | { | |
1803 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
1804 | DBG1(DBG_KNL, "querying policy failed: %s (%d)", | |
1805 | strerror(-err->error), -err->error); | |
1806 | break; | |
1807 | } | |
1808 | default: | |
1809 | hdr = NLMSG_NEXT(hdr, len); | |
1810 | continue; | |
1811 | case NLMSG_DONE: | |
1812 | break; | |
1813 | } | |
1814 | break; | |
1815 | } | |
1816 | } | |
7daf5226 | 1817 | |
507f26f6 TB |
1818 | if (policy == NULL) |
1819 | { | |
1820 | DBG2(DBG_KNL, "unable to query policy %R === %R %N", src_ts, dst_ts, | |
1821 | policy_dir_names, direction); | |
1822 | free(out); | |
1823 | return FAILED; | |
1824 | } | |
7daf5226 | 1825 | |
6180a558 MW |
1826 | if (policy->curlft.use_time) |
1827 | { | |
1828 | /* we need the monotonic time, but the kernel returns system time. */ | |
1829 | *use_time = time_monotonic(NULL) - (time(NULL) - policy->curlft.use_time); | |
1830 | } | |
1831 | else | |
1832 | { | |
1833 | *use_time = 0; | |
1834 | } | |
7daf5226 | 1835 | |
507f26f6 TB |
1836 | free(out); |
1837 | return SUCCESS; | |
1838 | } | |
1839 | ||
1840 | /** | |
1841 | * Implementation of kernel_interface_t.del_policy. | |
1842 | */ | |
1843 | static status_t del_policy(private_kernel_netlink_ipsec_t *this, | |
7daf5226 | 1844 | traffic_selector_t *src_ts, |
507f26f6 | 1845 | traffic_selector_t *dst_ts, |
ea625fab | 1846 | policy_dir_t direction, bool unrouted) |
507f26f6 TB |
1847 | { |
1848 | policy_entry_t *current, policy, *to_delete = NULL; | |
1849 | route_entry_t *route; | |
21bf86f7 | 1850 | netlink_buf_t request; |
507f26f6 TB |
1851 | struct nlmsghdr *hdr; |
1852 | struct xfrm_userpolicy_id *policy_id; | |
7daf5226 | 1853 | |
507f26f6 TB |
1854 | DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts, |
1855 | policy_dir_names, direction); | |
7daf5226 | 1856 | |
507f26f6 TB |
1857 | /* create a policy */ |
1858 | memset(&policy, 0, sizeof(policy_entry_t)); | |
1859 | policy.sel = ts2selector(src_ts, dst_ts); | |
1860 | policy.direction = direction; | |
7daf5226 | 1861 | |
507f26f6 | 1862 | /* find the policy */ |
3ac5a0db | 1863 | this->mutex->lock(this->mutex); |
3fb404d8 TB |
1864 | current = this->policies->get(this->policies, &policy); |
1865 | if (current) | |
507f26f6 | 1866 | { |
3fb404d8 TB |
1867 | to_delete = current; |
1868 | if (--to_delete->refcount > 0) | |
507f26f6 | 1869 | { |
3fb404d8 TB |
1870 | /* is used by more SAs, keep in kernel */ |
1871 | DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); | |
1872 | this->mutex->unlock(this->mutex); | |
1873 | return SUCCESS; | |
507f26f6 | 1874 | } |
3fb404d8 TB |
1875 | /* remove if last reference */ |
1876 | this->policies->remove(this->policies, to_delete); | |
507f26f6 | 1877 | } |
3ac5a0db | 1878 | this->mutex->unlock(this->mutex); |
507f26f6 TB |
1879 | if (!to_delete) |
1880 | { | |
1881 | DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts, | |
1882 | dst_ts, policy_dir_names, direction); | |
1883 | return NOT_FOUND; | |
1884 | } | |
7daf5226 | 1885 | |
507f26f6 | 1886 | memset(&request, 0, sizeof(request)); |
7daf5226 | 1887 | |
507f26f6 TB |
1888 | hdr = (struct nlmsghdr*)request; |
1889 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
1890 | hdr->nlmsg_type = XFRM_MSG_DELPOLICY; | |
1891 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)); | |
1892 | ||
1893 | policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr); | |
1894 | policy_id->sel = to_delete->sel; | |
1895 | policy_id->dir = direction; | |
7daf5226 | 1896 | |
507f26f6 TB |
1897 | route = to_delete->route; |
1898 | free(to_delete); | |
7daf5226 | 1899 | |
507f26f6 TB |
1900 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) |
1901 | { | |
1902 | DBG1(DBG_KNL, "unable to delete policy %R === %R %N", src_ts, dst_ts, | |
1903 | policy_dir_names, direction); | |
1904 | return FAILED; | |
1905 | } | |
1906 | ||
1907 | if (route) | |
1908 | { | |
1909 | if (charon->kernel_interface->del_route(charon->kernel_interface, | |
1910 | route->dst_net, route->prefixlen, route->gateway, | |
1911 | route->src_ip, route->if_name) != SUCCESS) | |
1912 | { | |
1913 | DBG1(DBG_KNL, "error uninstalling route installed with " | |
1914 | "policy %R === %R %N", src_ts, dst_ts, | |
1915 | policy_dir_names, direction); | |
7daf5226 | 1916 | } |
507f26f6 TB |
1917 | route_entry_destroy(route); |
1918 | } | |
1919 | return SUCCESS; | |
1920 | } | |
1921 | ||
1922 | /** | |
1923 | * Implementation of kernel_interface_t.destroy. | |
1924 | */ | |
1925 | static void destroy(private_kernel_netlink_ipsec_t *this) | |
1926 | { | |
3fb404d8 TB |
1927 | enumerator_t *enumerator; |
1928 | policy_entry_t *policy; | |
7daf5226 | 1929 | |
507f26f6 TB |
1930 | this->job->cancel(this->job); |
1931 | close(this->socket_xfrm_events); | |
1932 | this->socket_xfrm->destroy(this->socket_xfrm); | |
3fb404d8 | 1933 | enumerator = this->policies->create_enumerator(this->policies); |
19e0010f | 1934 | while (enumerator->enumerate(enumerator, &policy, &policy)) |
3fb404d8 TB |
1935 | { |
1936 | free(policy); | |
1937 | } | |
1938 | enumerator->destroy(enumerator); | |
507f26f6 | 1939 | this->policies->destroy(this->policies); |
3ac5a0db | 1940 | this->mutex->destroy(this->mutex); |
507f26f6 TB |
1941 | free(this); |
1942 | } | |
1943 | ||
ea625fab TB |
1944 | /** |
1945 | * Add bypass policies for IKE on the sockets used by charon | |
1946 | */ | |
1947 | static bool add_bypass_policies() | |
1948 | { | |
1949 | int fd, family, port; | |
1950 | enumerator_t *sockets; | |
e7c27b4f | 1951 | bool status = TRUE; |
7daf5226 | 1952 | |
ea625fab TB |
1953 | sockets = charon->socket->create_enumerator(charon->socket); |
1954 | while (sockets->enumerate(sockets, &fd, &family, &port)) | |
1955 | { | |
4a38687a | 1956 | struct xfrm_userpolicy_info policy; |
ea625fab | 1957 | u_int sol, ipsec_policy; |
7daf5226 | 1958 | |
ea625fab TB |
1959 | switch (family) |
1960 | { | |
1961 | case AF_INET: | |
1962 | sol = SOL_IP; | |
4a38687a | 1963 | ipsec_policy = IP_XFRM_POLICY; |
ea625fab TB |
1964 | break; |
1965 | case AF_INET6: | |
ea625fab | 1966 | sol = SOL_IPV6; |
4a38687a | 1967 | ipsec_policy = IPV6_XFRM_POLICY; |
ea625fab | 1968 | break; |
dbb24102 MW |
1969 | default: |
1970 | continue; | |
ea625fab | 1971 | } |
7daf5226 | 1972 | |
ea625fab | 1973 | memset(&policy, 0, sizeof(policy)); |
4a38687a MW |
1974 | policy.action = XFRM_POLICY_ALLOW; |
1975 | policy.sel.family = family; | |
7daf5226 | 1976 | |
4a38687a | 1977 | policy.dir = XFRM_POLICY_OUT; |
ea625fab TB |
1978 | if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0) |
1979 | { | |
1980 | DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s", | |
1981 | strerror(errno)); | |
e7c27b4f TB |
1982 | status = FALSE; |
1983 | break; | |
ea625fab | 1984 | } |
4a38687a | 1985 | policy.dir = XFRM_POLICY_IN; |
ea625fab TB |
1986 | if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0) |
1987 | { | |
7daf5226 | 1988 | DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s", |
ea625fab | 1989 | strerror(errno)); |
e7c27b4f TB |
1990 | status = FALSE; |
1991 | break; | |
ea625fab TB |
1992 | } |
1993 | } | |
e7c27b4f TB |
1994 | sockets->destroy(sockets); |
1995 | return status; | |
ea625fab TB |
1996 | } |
1997 | ||
507f26f6 TB |
1998 | /* |
1999 | * Described in header. | |
2000 | */ | |
2001 | kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() | |
2002 | { | |
2003 | private_kernel_netlink_ipsec_t *this = malloc_thing(private_kernel_netlink_ipsec_t); | |
2004 | struct sockaddr_nl addr; | |
469083cc | 2005 | int fd; |
7daf5226 | 2006 | |
507f26f6 TB |
2007 | /* public functions */ |
2008 | this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; | |
2009 | this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi; | |
888af963 | 2010 | this->public.interface.add_sa = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,lifetime_cfg_t*,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,u_int16_t,bool,bool))add_sa; |
ea625fab | 2011 | this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,u_int16_t,host_t*,host_t*,host_t*,host_t*,bool,bool))update_sa; |
2ad51539 | 2012 | this->public.interface.query_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int64_t*))query_sa; |
d24a74c5 | 2013 | this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,protocol_id_t,u_int16_t))del_sa; |
ea625fab | 2014 | this->public.interface.add_policy = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t,protocol_id_t,u_int32_t,ipsec_mode_t,u_int16_t,u_int16_t,bool))add_policy; |
507f26f6 | 2015 | this->public.interface.query_policy = (status_t(*)(kernel_ipsec_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy; |
ea625fab | 2016 | this->public.interface.del_policy = (status_t(*)(kernel_ipsec_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,bool))del_policy; |
507f26f6 TB |
2017 | this->public.interface.destroy = (void(*)(kernel_ipsec_t*)) destroy; |
2018 | ||
2019 | /* private members */ | |
3fb404d8 | 2020 | this->policies = hashtable_create((hashtable_hash_t)policy_hash, |
0dbd9788 | 2021 | (hashtable_equals_t)policy_equals, 32); |
3901937d | 2022 | this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); |
507f26f6 TB |
2023 | this->install_routes = lib->settings->get_bool(lib->settings, |
2024 | "charon.install_routes", TRUE); | |
7daf5226 | 2025 | |
469083cc MW |
2026 | /* disable lifetimes for allocated SPIs in kernel */ |
2027 | fd = open("/proc/sys/net/core/xfrm_acq_expires", O_WRONLY); | |
2028 | if (fd) | |
2029 | { | |
4b1cd5a3 | 2030 | ignore_result(write(fd, "165", 3)); |
469083cc MW |
2031 | close(fd); |
2032 | } | |
7daf5226 | 2033 | |
507f26f6 | 2034 | this->socket_xfrm = netlink_socket_create(NETLINK_XFRM); |
7daf5226 | 2035 | |
507f26f6 TB |
2036 | memset(&addr, 0, sizeof(addr)); |
2037 | addr.nl_family = AF_NETLINK; | |
7daf5226 | 2038 | |
e7f4fc53 | 2039 | /* create and bind XFRM socket for ACQUIRE, EXPIRE, MIGRATE & MAPPING */ |
507f26f6 TB |
2040 | this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); |
2041 | if (this->socket_xfrm_events <= 0) | |
2042 | { | |
2043 | charon->kill(charon, "unable to create XFRM event socket"); | |
2044 | } | |
e7f4fc53 AS |
2045 | addr.nl_groups = XFRMNLGRP(ACQUIRE) | XFRMNLGRP(EXPIRE) | |
2046 | XFRMNLGRP(MIGRATE) | XFRMNLGRP(MAPPING); | |
507f26f6 TB |
2047 | if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr))) |
2048 | { | |
2049 | charon->kill(charon, "unable to bind XFRM event socket"); | |
2050 | } | |
7daf5226 | 2051 | |
67c3875c MW |
2052 | /* add bypass policies on the sockets used by charon */ |
2053 | if (!add_bypass_policies()) | |
2054 | { | |
2055 | charon->kill(charon, "unable to add bypass policies on sockets"); | |
2056 | } | |
2057 | ||
507f26f6 TB |
2058 | this->job = callback_job_create((callback_job_cb_t)receive_events, |
2059 | this, NULL, NULL); | |
2060 | charon->processor->queue_job(charon->processor, (job_t*)this->job); | |
7daf5226 | 2061 | |
507f26f6 TB |
2062 | return &this->public; |
2063 | } |