]>
Commit | Line | Data |
---|---|---|
507f26f6 TB |
1 | /* |
2 | * Copyright (C) 2006-2008 Tobias Brunner | |
3 | * Copyright (C) 2005-2007 Martin Willi | |
4 | * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser | |
5 | * Copyright (C) 2006 Daniel Roethlisberger | |
6 | * Copyright (C) 2005 Jan Hutter | |
7 | * Hochschule fuer Technik Rapperswil | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by the | |
11 | * Free Software Foundation; either version 2 of the License, or (at your | |
12 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 | * for more details. | |
18 | * | |
19 | * $Id$ | |
20 | */ | |
21 | ||
22 | #include <sys/types.h> | |
23 | #include <sys/socket.h> | |
24 | #include <sys/time.h> | |
25 | #include <linux/netlink.h> | |
26 | #include <linux/rtnetlink.h> | |
27 | #include <linux/xfrm.h> | |
28 | #include <linux/udp.h> | |
29 | #include <netinet/in.h> | |
30 | #include <pthread.h> | |
31 | #include <unistd.h> | |
32 | #include <errno.h> | |
33 | #include <string.h> | |
34 | ||
35 | #include "kernel_netlink_ipsec.h" | |
36 | #include "kernel_netlink_shared.h" | |
37 | ||
38 | #include <daemon.h> | |
39 | #include <utils/linked_list.h> | |
40 | #include <processing/jobs/callback_job.h> | |
41 | #include <processing/jobs/acquire_job.h> | |
42 | #include <processing/jobs/rekey_child_sa_job.h> | |
43 | #include <processing/jobs/delete_child_sa_job.h> | |
44 | ||
45 | /** required for Linux 2.6.26 kernel and later */ | |
46 | #ifndef XFRM_STATE_AF_UNSPEC | |
47 | #define XFRM_STATE_AF_UNSPEC 32 | |
48 | #endif | |
49 | ||
50 | /** default priority of installed policies */ | |
51 | #define PRIO_LOW 3000 | |
52 | #define PRIO_HIGH 2000 | |
53 | ||
54 | /** | |
55 | * returns a pointer to the first rtattr following the nlmsghdr *nlh and the | |
56 | * 'usual' netlink data x like 'struct xfrm_usersa_info' | |
57 | */ | |
58 | #define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(x)))) | |
59 | /** | |
60 | * returns a pointer to the next rtattr following rta. | |
61 | * !!! do not use this to parse messages. use RTA_NEXT and RTA_OK instead !!! | |
62 | */ | |
63 | #define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len))) | |
64 | /** | |
65 | * returns the total size of attached rta data | |
66 | * (after 'usual' netlink data x like 'struct xfrm_usersa_info') | |
67 | */ | |
68 | #define XFRM_PAYLOAD(nlh, x) NLMSG_PAYLOAD(nlh, sizeof(x)) | |
69 | ||
70 | typedef struct kernel_algorithm_t kernel_algorithm_t; | |
71 | ||
72 | /** | |
73 | * Mapping from the algorithms defined in IKEv2 to | |
74 | * kernel level algorithm names and their key length | |
75 | */ | |
76 | struct kernel_algorithm_t { | |
77 | /** | |
78 | * Identifier specified in IKEv2 | |
79 | */ | |
80 | int ikev2_id; | |
81 | ||
82 | /** | |
83 | * Name of the algorithm, as used as kernel identifier | |
84 | */ | |
85 | char *name; | |
86 | ||
87 | /** | |
88 | * Key length in bits, if fixed size | |
89 | */ | |
90 | u_int key_size; | |
91 | }; | |
92 | ||
93 | ENUM(policy_dir_names, POLICY_IN, POLICY_FWD, | |
94 | "in", | |
95 | "out", | |
96 | "fwd" | |
97 | ); | |
98 | ||
99 | #define END_OF_LIST -1 | |
100 | ||
101 | /** | |
102 | * Algorithms for encryption | |
103 | */ | |
104 | static kernel_algorithm_t encryption_algs[] = { | |
105 | /* {ENCR_DES_IV64, "***", 0}, */ | |
106 | {ENCR_DES, "des", 64}, | |
107 | {ENCR_3DES, "des3_ede", 192}, | |
108 | /* {ENCR_RC5, "***", 0}, */ | |
109 | /* {ENCR_IDEA, "***", 0}, */ | |
110 | {ENCR_CAST, "cast128", 0}, | |
111 | {ENCR_BLOWFISH, "blowfish", 0}, | |
112 | /* {ENCR_3IDEA, "***", 0}, */ | |
113 | /* {ENCR_DES_IV32, "***", 0}, */ | |
114 | {ENCR_NULL, "cipher_null", 0}, | |
115 | {ENCR_AES_CBC, "aes", 0}, | |
116 | /* {ENCR_AES_CTR, "***", 0}, */ | |
117 | {ENCR_AES_CCM_ICV8, "rfc4309(ccm(aes))", 64}, /* key_size = ICV size */ | |
118 | {ENCR_AES_CCM_ICV12, "rfc4309(ccm(aes))", 96}, /* key_size = ICV size */ | |
119 | {ENCR_AES_CCM_ICV16, "rfc4309(ccm(aes))", 128}, /* key_size = ICV size */ | |
120 | {ENCR_AES_GCM_ICV8, "rfc4106(gcm(aes))", 64}, /* key_size = ICV size */ | |
121 | {ENCR_AES_GCM_ICV12, "rfc4106(gcm(aes))", 96}, /* key_size = ICV size */ | |
122 | {ENCR_AES_GCM_ICV16, "rfc4106(gcm(aes))", 128}, /* key_size = ICV size */ | |
123 | {END_OF_LIST, NULL, 0}, | |
124 | }; | |
125 | ||
126 | /** | |
127 | * Algorithms for integrity protection | |
128 | */ | |
129 | static kernel_algorithm_t integrity_algs[] = { | |
130 | {AUTH_HMAC_MD5_96, "md5", 128}, | |
131 | {AUTH_HMAC_SHA1_96, "sha1", 160}, | |
132 | {AUTH_HMAC_SHA2_256_128, "sha256", 256}, | |
133 | {AUTH_HMAC_SHA2_384_192, "sha384", 384}, | |
134 | {AUTH_HMAC_SHA2_512_256, "sha512", 512}, | |
135 | /* {AUTH_DES_MAC, "***", 0}, */ | |
136 | /* {AUTH_KPDK_MD5, "***", 0}, */ | |
137 | {AUTH_AES_XCBC_96, "xcbc(aes)", 128}, | |
138 | {END_OF_LIST, NULL, 0}, | |
139 | }; | |
140 | ||
141 | /** | |
142 | * Algorithms for IPComp | |
143 | */ | |
144 | static kernel_algorithm_t compression_algs[] = { | |
145 | /* {IPCOMP_OUI, "***", 0}, */ | |
146 | {IPCOMP_DEFLATE, "deflate", 0}, | |
147 | {IPCOMP_LZS, "lzs", 0}, | |
148 | {IPCOMP_LZJH, "lzjh", 0}, | |
149 | {END_OF_LIST, NULL, 0}, | |
150 | }; | |
151 | ||
152 | /** | |
153 | * Look up a kernel algorithm name and its key size | |
154 | */ | |
155 | static char* lookup_algorithm(kernel_algorithm_t *kernel_algo, | |
156 | u_int16_t ikev2_algo, u_int16_t *key_size) | |
157 | { | |
158 | while (kernel_algo->ikev2_id != END_OF_LIST) | |
159 | { | |
160 | if (ikev2_algo == kernel_algo->ikev2_id) | |
161 | { | |
162 | /* match, evaluate key length */ | |
163 | if (key_size && *key_size == 0) | |
164 | { /* update key size if not set */ | |
165 | *key_size = kernel_algo->key_size; | |
166 | } | |
167 | return kernel_algo->name; | |
168 | } | |
169 | kernel_algo++; | |
170 | } | |
171 | return NULL; | |
172 | } | |
173 | ||
174 | typedef struct route_entry_t route_entry_t; | |
175 | ||
176 | /** | |
177 | * installed routing entry | |
178 | */ | |
179 | struct route_entry_t { | |
180 | /** Name of the interface the route is bound to */ | |
181 | char *if_name; | |
182 | ||
183 | /** Source ip of the route */ | |
184 | host_t *src_ip; | |
185 | ||
186 | /** gateway for this route */ | |
187 | host_t *gateway; | |
188 | ||
189 | /** Destination net */ | |
190 | chunk_t dst_net; | |
191 | ||
192 | /** Destination net prefixlen */ | |
193 | u_int8_t prefixlen; | |
194 | }; | |
195 | ||
196 | /** | |
197 | * destroy an route_entry_t object | |
198 | */ | |
199 | static void route_entry_destroy(route_entry_t *this) | |
200 | { | |
201 | free(this->if_name); | |
202 | this->src_ip->destroy(this->src_ip); | |
203 | this->gateway->destroy(this->gateway); | |
204 | chunk_free(&this->dst_net); | |
205 | free(this); | |
206 | } | |
207 | ||
208 | typedef struct policy_entry_t policy_entry_t; | |
209 | ||
210 | /** | |
211 | * installed kernel policy. | |
212 | */ | |
213 | struct policy_entry_t { | |
214 | ||
215 | /** direction of this policy: in, out, forward */ | |
216 | u_int8_t direction; | |
217 | ||
218 | /** reqid of the policy */ | |
219 | u_int32_t reqid; | |
220 | ||
221 | /** parameters of installed policy */ | |
222 | struct xfrm_selector sel; | |
223 | ||
224 | /** associated route installed for this policy */ | |
225 | route_entry_t *route; | |
226 | ||
227 | /** by how many CHILD_SA's this policy is used */ | |
228 | u_int refcount; | |
229 | }; | |
230 | ||
231 | typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t; | |
232 | ||
233 | /** | |
234 | * Private variables and functions of kernel_netlink class. | |
235 | */ | |
236 | struct private_kernel_netlink_ipsec_t { | |
237 | /** | |
238 | * Public part of the kernel_netlink_t object. | |
239 | */ | |
240 | kernel_netlink_ipsec_t public; | |
241 | ||
242 | /** | |
243 | * mutex to lock access to various lists | |
244 | */ | |
245 | pthread_mutex_t mutex; | |
246 | ||
247 | /** | |
248 | * List of installed policies (policy_entry_t) | |
249 | */ | |
250 | linked_list_t *policies; | |
251 | ||
252 | /** | |
253 | * job receiving netlink events | |
254 | */ | |
255 | callback_job_t *job; | |
256 | ||
257 | /** | |
258 | * Netlink xfrm socket (IPsec) | |
259 | */ | |
260 | netlink_socket_t *socket_xfrm; | |
261 | ||
262 | /** | |
263 | * netlink xfrm socket to receive acquire and expire events | |
264 | */ | |
265 | int socket_xfrm_events; | |
266 | ||
267 | /** | |
268 | * whether to install routes along policies | |
269 | */ | |
270 | bool install_routes; | |
271 | }; | |
272 | ||
273 | /** | |
274 | * convert a IKEv2 specific protocol identifier to the kernel one | |
275 | */ | |
276 | static u_int8_t proto_ike2kernel(protocol_id_t proto) | |
277 | { | |
278 | switch (proto) | |
279 | { | |
280 | case PROTO_ESP: | |
281 | return IPPROTO_ESP; | |
282 | case PROTO_AH: | |
283 | return IPPROTO_AH; | |
284 | default: | |
285 | return proto; | |
286 | } | |
287 | } | |
288 | ||
289 | /** | |
290 | * reverse of ike2kernel | |
291 | */ | |
292 | static protocol_id_t proto_kernel2ike(u_int8_t proto) | |
293 | { | |
294 | switch (proto) | |
295 | { | |
296 | case IPPROTO_ESP: | |
297 | return PROTO_ESP; | |
298 | case IPPROTO_AH: | |
299 | return PROTO_AH; | |
300 | default: | |
301 | return proto; | |
302 | } | |
303 | } | |
304 | ||
305 | /** | |
306 | * convert a host_t to a struct xfrm_address | |
307 | */ | |
308 | static void host2xfrm(host_t *host, xfrm_address_t *xfrm) | |
309 | { | |
310 | chunk_t chunk = host->get_address(host); | |
311 | memcpy(xfrm, chunk.ptr, min(chunk.len, sizeof(xfrm_address_t))); | |
312 | } | |
313 | ||
314 | /** | |
315 | * convert a traffic selector address range to subnet and its mask. | |
316 | */ | |
317 | static void ts2subnet(traffic_selector_t* ts, | |
318 | xfrm_address_t *net, u_int8_t *mask) | |
319 | { | |
320 | /* there is no way to do this cleanly, as the address range may | |
321 | * be anything else but a subnet. We use from_addr as subnet | |
322 | * and try to calculate a usable subnet mask. | |
323 | */ | |
324 | int byte, bit; | |
325 | bool found = FALSE; | |
326 | chunk_t from, to; | |
327 | size_t size = (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) ? 4 : 16; | |
328 | ||
329 | from = ts->get_from_address(ts); | |
330 | to = ts->get_to_address(ts); | |
331 | ||
332 | *mask = (size * 8); | |
333 | /* go trough all bits of the addresses, beginning in the front. | |
334 | * as long as they are equal, the subnet gets larger | |
335 | */ | |
336 | for (byte = 0; byte < size; byte++) | |
337 | { | |
338 | for (bit = 7; bit >= 0; bit--) | |
339 | { | |
340 | if ((1<<bit & from.ptr[byte]) != (1<<bit & to.ptr[byte])) | |
341 | { | |
342 | *mask = ((7 - bit) + (byte * 8)); | |
343 | found = TRUE; | |
344 | break; | |
345 | } | |
346 | } | |
347 | if (found) | |
348 | { | |
349 | break; | |
350 | } | |
351 | } | |
352 | memcpy(net, from.ptr, from.len); | |
353 | chunk_free(&from); | |
354 | chunk_free(&to); | |
355 | } | |
356 | ||
357 | /** | |
358 | * convert a traffic selector port range to port/portmask | |
359 | */ | |
360 | static void ts2ports(traffic_selector_t* ts, | |
361 | u_int16_t *port, u_int16_t *mask) | |
362 | { | |
363 | /* linux does not seem to accept complex portmasks. Only | |
364 | * any or a specific port is allowed. We set to any, if we have | |
365 | * a port range, or to a specific, if we have one port only. | |
366 | */ | |
367 | u_int16_t from, to; | |
368 | ||
369 | from = ts->get_from_port(ts); | |
370 | to = ts->get_to_port(ts); | |
371 | ||
372 | if (from == to) | |
373 | { | |
374 | *port = htons(from); | |
375 | *mask = ~0; | |
376 | } | |
377 | else | |
378 | { | |
379 | *port = 0; | |
380 | *mask = 0; | |
381 | } | |
382 | } | |
383 | ||
384 | /** | |
385 | * convert a pair of traffic_selectors to a xfrm_selector | |
386 | */ | |
387 | static struct xfrm_selector ts2selector(traffic_selector_t *src, | |
388 | traffic_selector_t *dst) | |
389 | { | |
390 | struct xfrm_selector sel; | |
391 | ||
392 | memset(&sel, 0, sizeof(sel)); | |
393 | sel.family = (src->get_type(src) == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; | |
394 | /* src or dest proto may be "any" (0), use more restrictive one */ | |
395 | sel.proto = max(src->get_protocol(src), dst->get_protocol(dst)); | |
396 | ts2subnet(dst, &sel.daddr, &sel.prefixlen_d); | |
397 | ts2subnet(src, &sel.saddr, &sel.prefixlen_s); | |
398 | ts2ports(dst, &sel.dport, &sel.dport_mask); | |
399 | ts2ports(src, &sel.sport, &sel.sport_mask); | |
400 | sel.ifindex = 0; | |
401 | sel.user = 0; | |
402 | ||
403 | return sel; | |
404 | } | |
405 | ||
406 | ||
407 | /** | |
408 | * process a XFRM_MSG_ACQUIRE from kernel | |
409 | */ | |
410 | static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr) | |
411 | { | |
412 | u_int32_t reqid = 0; | |
413 | int proto = 0; | |
414 | job_t *job; | |
415 | struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire); | |
416 | size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl); | |
417 | ||
418 | if (RTA_OK(rtattr, rtsize)) | |
419 | { | |
420 | if (rtattr->rta_type == XFRMA_TMPL) | |
421 | { | |
422 | struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr); | |
423 | reqid = tmpl->reqid; | |
424 | proto = tmpl->id.proto; | |
425 | } | |
426 | } | |
427 | switch (proto) | |
428 | { | |
429 | case 0: | |
430 | case IPPROTO_ESP: | |
431 | case IPPROTO_AH: | |
432 | break; | |
433 | default: | |
434 | /* acquire for AH/ESP only, not for IPCOMP */ | |
435 | return; | |
436 | } | |
437 | if (reqid == 0) | |
438 | { | |
439 | DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found"); | |
440 | return; | |
441 | } | |
442 | DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE"); | |
443 | DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid {%d}", reqid); | |
444 | job = (job_t*)acquire_job_create(reqid); | |
445 | charon->processor->queue_job(charon->processor, job); | |
446 | } | |
447 | ||
448 | /** | |
449 | * process a XFRM_MSG_EXPIRE from kernel | |
450 | */ | |
451 | static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr) | |
452 | { | |
453 | job_t *job; | |
454 | protocol_id_t protocol; | |
455 | u_int32_t spi, reqid; | |
456 | struct xfrm_user_expire *expire; | |
457 | ||
458 | expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr); | |
459 | protocol = proto_kernel2ike(expire->state.id.proto); | |
460 | spi = expire->state.id.spi; | |
461 | reqid = expire->state.reqid; | |
462 | ||
463 | DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE"); | |
464 | ||
465 | if (protocol != PROTO_ESP && protocol != PROTO_AH) | |
466 | { | |
467 | DBG2(DBG_KNL, "ignoring XFRM_MSG_EXPIRE for SA with SPI %.8x and reqid {%d} " | |
468 | "which is not a CHILD_SA", ntohl(spi), reqid); | |
469 | return; | |
470 | } | |
471 | ||
472 | DBG1(DBG_KNL, "creating %s job for %N CHILD_SA with SPI %.8x and reqid {%d}", | |
473 | expire->hard ? "delete" : "rekey", protocol_id_names, | |
474 | protocol, ntohl(spi), reqid); | |
475 | if (expire->hard) | |
476 | { | |
477 | job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi); | |
478 | } | |
479 | else | |
480 | { | |
481 | job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi); | |
482 | } | |
483 | charon->processor->queue_job(charon->processor, job); | |
484 | } | |
485 | ||
486 | /** | |
487 | * Receives events from kernel | |
488 | */ | |
489 | static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this) | |
490 | { | |
491 | char response[1024]; | |
492 | struct nlmsghdr *hdr = (struct nlmsghdr*)response; | |
493 | struct sockaddr_nl addr; | |
494 | socklen_t addr_len = sizeof(addr); | |
495 | int len, oldstate; | |
496 | ||
497 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); | |
498 | len = recvfrom(this->socket_xfrm_events, response, sizeof(response), 0, | |
499 | (struct sockaddr*)&addr, &addr_len); | |
500 | pthread_setcancelstate(oldstate, NULL); | |
501 | ||
502 | if (len < 0) | |
503 | { | |
504 | switch (errno) | |
505 | { | |
506 | case EINTR: | |
507 | /* interrupted, try again */ | |
508 | return JOB_REQUEUE_DIRECT; | |
509 | case EAGAIN: | |
510 | /* no data ready, select again */ | |
511 | return JOB_REQUEUE_DIRECT; | |
512 | default: | |
513 | DBG1(DBG_KNL, "unable to receive from xfrm event socket"); | |
514 | sleep(1); | |
515 | return JOB_REQUEUE_FAIR; | |
516 | } | |
517 | } | |
518 | ||
519 | if (addr.nl_pid != 0) | |
520 | { /* not from kernel. not interested, try another one */ | |
521 | return JOB_REQUEUE_DIRECT; | |
522 | } | |
523 | ||
524 | while (NLMSG_OK(hdr, len)) | |
525 | { | |
526 | switch (hdr->nlmsg_type) | |
527 | { | |
528 | case XFRM_MSG_ACQUIRE: | |
529 | process_acquire(this, hdr); | |
530 | break; | |
531 | case XFRM_MSG_EXPIRE: | |
532 | process_expire(this, hdr); | |
533 | break; | |
534 | default: | |
535 | break; | |
536 | } | |
537 | hdr = NLMSG_NEXT(hdr, len); | |
538 | } | |
539 | return JOB_REQUEUE_DIRECT; | |
540 | } | |
541 | ||
542 | /** | |
543 | * Tries to find an ip address of a local interface that is included in the | |
544 | * supplied traffic selector. | |
545 | */ | |
546 | static status_t get_address_by_ts(private_kernel_netlink_ipsec_t *this, | |
547 | traffic_selector_t *ts, host_t **ip) | |
548 | { | |
549 | enumerator_t *addrs; | |
550 | host_t *host; | |
551 | int family; | |
552 | bool found = FALSE; | |
553 | ||
554 | DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts); | |
555 | ||
556 | /* if we have a family which includes localhost, we do not | |
557 | * search for an IP, we use the default */ | |
558 | family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6; | |
559 | ||
560 | if (family == AF_INET) | |
561 | { | |
562 | host = host_create_from_string("127.0.0.1", 0); | |
563 | } | |
564 | else | |
565 | { | |
566 | host = host_create_from_string("::1", 0); | |
567 | } | |
568 | ||
569 | if (ts->includes(ts, host)) | |
570 | { | |
571 | *ip = host_create_any(family); | |
572 | host->destroy(host); | |
573 | DBG2(DBG_KNL, "using host %H", *ip); | |
574 | return SUCCESS; | |
575 | } | |
576 | host->destroy(host); | |
577 | ||
578 | addrs = charon->kernel_interface->create_address_enumerator( | |
579 | charon->kernel_interface, TRUE, TRUE); | |
580 | while (addrs->enumerate(addrs, (void**)&host)) | |
581 | { | |
582 | if (ts->includes(ts, host)) | |
583 | { | |
584 | found = TRUE; | |
585 | *ip = host->clone(host); | |
586 | break; | |
587 | } | |
588 | } | |
589 | addrs->destroy(addrs); | |
590 | ||
591 | if (!found) | |
592 | { | |
593 | DBG1(DBG_KNL, "no local address found in traffic selector %R", ts); | |
594 | return FAILED; | |
595 | } | |
596 | DBG2(DBG_KNL, "using host %H", *ip); | |
597 | return SUCCESS; | |
598 | } | |
599 | ||
600 | /** | |
601 | * Get an SPI for a specific protocol from the kernel. | |
602 | */ | |
603 | static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this, | |
604 | host_t *src, host_t *dst, u_int8_t proto, u_int32_t min, u_int32_t max, | |
605 | u_int32_t reqid, u_int32_t *spi) | |
606 | { | |
607 | unsigned char request[NETLINK_BUFFER_SIZE]; | |
608 | struct nlmsghdr *hdr, *out; | |
609 | struct xfrm_userspi_info *userspi; | |
610 | u_int32_t received_spi = 0; | |
611 | size_t len; | |
612 | ||
613 | memset(&request, 0, sizeof(request)); | |
614 | ||
615 | hdr = (struct nlmsghdr*)request; | |
616 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
617 | hdr->nlmsg_type = XFRM_MSG_ALLOCSPI; | |
618 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userspi_info)); | |
619 | ||
620 | userspi = (struct xfrm_userspi_info*)NLMSG_DATA(hdr); | |
621 | host2xfrm(src, &userspi->info.saddr); | |
622 | host2xfrm(dst, &userspi->info.id.daddr); | |
623 | userspi->info.id.proto = proto; | |
624 | userspi->info.mode = TRUE; /* tunnel mode */ | |
625 | userspi->info.reqid = reqid; | |
626 | userspi->info.family = src->get_family(src); | |
627 | userspi->min = min; | |
628 | userspi->max = max; | |
629 | ||
630 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) | |
631 | { | |
632 | hdr = out; | |
633 | while (NLMSG_OK(hdr, len)) | |
634 | { | |
635 | switch (hdr->nlmsg_type) | |
636 | { | |
637 | case XFRM_MSG_NEWSA: | |
638 | { | |
639 | struct xfrm_usersa_info* usersa = NLMSG_DATA(hdr); | |
640 | received_spi = usersa->id.spi; | |
641 | break; | |
642 | } | |
643 | case NLMSG_ERROR: | |
644 | { | |
645 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
646 | ||
647 | DBG1(DBG_KNL, "allocating SPI failed: %s (%d)", | |
648 | strerror(-err->error), -err->error); | |
649 | break; | |
650 | } | |
651 | default: | |
652 | hdr = NLMSG_NEXT(hdr, len); | |
653 | continue; | |
654 | case NLMSG_DONE: | |
655 | break; | |
656 | } | |
657 | break; | |
658 | } | |
659 | free(out); | |
660 | } | |
661 | ||
662 | if (received_spi == 0) | |
663 | { | |
664 | return FAILED; | |
665 | } | |
666 | ||
667 | *spi = received_spi; | |
668 | return SUCCESS; | |
669 | } | |
670 | ||
671 | /** | |
672 | * Implementation of kernel_interface_t.get_spi. | |
673 | */ | |
674 | static status_t get_spi(private_kernel_netlink_ipsec_t *this, | |
675 | host_t *src, host_t *dst, | |
676 | protocol_id_t protocol, u_int32_t reqid, | |
677 | u_int32_t *spi) | |
678 | { | |
679 | DBG2(DBG_KNL, "getting SPI for reqid {%d}", reqid); | |
680 | ||
681 | if (get_spi_internal(this, src, dst, proto_ike2kernel(protocol), | |
682 | 0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS) | |
683 | { | |
684 | DBG1(DBG_KNL, "unable to get SPI for reqid {%d}", reqid); | |
685 | return FAILED; | |
686 | } | |
687 | ||
688 | DBG2(DBG_KNL, "got SPI %.8x for reqid {%d}", ntohl(*spi), reqid); | |
689 | ||
690 | return SUCCESS; | |
691 | } | |
692 | ||
693 | /** | |
694 | * Implementation of kernel_interface_t.get_cpi. | |
695 | */ | |
696 | static status_t get_cpi(private_kernel_netlink_ipsec_t *this, | |
697 | host_t *src, host_t *dst, | |
698 | u_int32_t reqid, u_int16_t *cpi) | |
699 | { | |
700 | u_int32_t received_spi = 0; | |
701 | ||
702 | DBG2(DBG_KNL, "getting CPI for reqid {%d}", reqid); | |
703 | ||
704 | if (get_spi_internal(this, src, dst, | |
705 | IPPROTO_COMP, 0x100, 0xEFFF, reqid, &received_spi) != SUCCESS) | |
706 | { | |
707 | DBG1(DBG_KNL, "unable to get CPI for reqid {%d}", reqid); | |
708 | return FAILED; | |
709 | } | |
710 | ||
711 | *cpi = htons((u_int16_t)ntohl(received_spi)); | |
712 | ||
713 | DBG2(DBG_KNL, "got CPI %.4x for reqid {%d}", ntohs(*cpi), reqid); | |
714 | ||
715 | return SUCCESS; | |
716 | } | |
717 | ||
718 | /** | |
719 | * Implementation of kernel_interface_t.add_sa. | |
720 | */ | |
721 | static status_t add_sa(private_kernel_netlink_ipsec_t *this, | |
722 | host_t *src, host_t *dst, u_int32_t spi, | |
723 | protocol_id_t protocol, u_int32_t reqid, | |
724 | u_int64_t expire_soft, u_int64_t expire_hard, | |
725 | u_int16_t enc_alg, u_int16_t enc_size, | |
726 | u_int16_t int_alg, u_int16_t int_size, | |
727 | prf_plus_t *prf_plus, mode_t mode, | |
728 | u_int16_t ipcomp, bool encap, | |
729 | bool replace) | |
730 | { | |
731 | unsigned char request[NETLINK_BUFFER_SIZE]; | |
732 | char *alg_name; | |
733 | /* additional 4 octets KEYMAT required for AES-GCM as of RFC4106 8.1. */ | |
734 | u_int16_t add_keymat = 32; | |
735 | struct nlmsghdr *hdr; | |
736 | struct xfrm_usersa_info *sa; | |
737 | ||
738 | memset(&request, 0, sizeof(request)); | |
739 | ||
740 | DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}", ntohl(spi), reqid); | |
741 | ||
742 | hdr = (struct nlmsghdr*)request; | |
743 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
744 | hdr->nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; | |
745 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); | |
746 | ||
747 | sa = (struct xfrm_usersa_info*)NLMSG_DATA(hdr); | |
748 | host2xfrm(src, &sa->saddr); | |
749 | host2xfrm(dst, &sa->id.daddr); | |
750 | sa->id.spi = spi; | |
751 | sa->id.proto = proto_ike2kernel(protocol); | |
752 | sa->family = src->get_family(src); | |
753 | sa->mode = mode; | |
754 | if (mode == MODE_TUNNEL) | |
755 | { | |
756 | sa->flags |= XFRM_STATE_AF_UNSPEC; | |
757 | } | |
758 | sa->replay_window = (protocol == IPPROTO_COMP) ? 0 : 32; | |
759 | sa->reqid = reqid; | |
760 | /* we currently do not expire SAs by volume/packet count */ | |
761 | sa->lft.soft_byte_limit = XFRM_INF; | |
762 | sa->lft.hard_byte_limit = XFRM_INF; | |
763 | sa->lft.soft_packet_limit = XFRM_INF; | |
764 | sa->lft.hard_packet_limit = XFRM_INF; | |
765 | /* we use lifetimes since added, not since used */ | |
766 | sa->lft.soft_add_expires_seconds = expire_soft; | |
767 | sa->lft.hard_add_expires_seconds = expire_hard; | |
768 | sa->lft.soft_use_expires_seconds = 0; | |
769 | sa->lft.hard_use_expires_seconds = 0; | |
770 | ||
771 | struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_info); | |
772 | ||
773 | switch (enc_alg) | |
774 | { | |
775 | case ENCR_UNDEFINED: | |
776 | /* no encryption */ | |
777 | break; | |
778 | case ENCR_AES_CCM_ICV8: | |
779 | case ENCR_AES_CCM_ICV12: | |
780 | case ENCR_AES_CCM_ICV16: | |
781 | /* AES-CCM needs only 3 additional octets KEYMAT as of RFC 4309 7.1. */ | |
782 | add_keymat = 24; | |
783 | /* fall-through */ | |
784 | case ENCR_AES_GCM_ICV8: | |
785 | case ENCR_AES_GCM_ICV12: | |
786 | case ENCR_AES_GCM_ICV16: | |
787 | { | |
788 | u_int16_t icv_size = 0; | |
789 | rthdr->rta_type = XFRMA_ALG_AEAD; | |
790 | alg_name = lookup_algorithm(encryption_algs, enc_alg, &icv_size); | |
791 | if (alg_name == NULL) | |
792 | { | |
793 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", | |
794 | encryption_algorithm_names, enc_alg); | |
795 | return FAILED; | |
796 | } | |
797 | DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", | |
798 | encryption_algorithm_names, enc_alg, enc_size); | |
799 | ||
800 | /* additional KEYMAT required */ | |
801 | enc_size += add_keymat; | |
802 | ||
803 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_size / 8); | |
804 | hdr->nlmsg_len += rthdr->rta_len; | |
805 | if (hdr->nlmsg_len > sizeof(request)) | |
806 | { | |
807 | return FAILED; | |
808 | } | |
809 | ||
810 | struct xfrm_algo_aead* algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr); | |
811 | algo->alg_key_len = enc_size; | |
812 | algo->alg_icv_len = icv_size; | |
813 | strcpy(algo->alg_name, alg_name); | |
814 | prf_plus->get_bytes(prf_plus, enc_size / 8, algo->alg_key); | |
815 | ||
816 | rthdr = XFRM_RTA_NEXT(rthdr); | |
817 | break; | |
818 | } | |
819 | default: | |
820 | { | |
821 | rthdr->rta_type = XFRMA_ALG_CRYPT; | |
822 | alg_name = lookup_algorithm(encryption_algs, enc_alg, &enc_size); | |
823 | if (alg_name == NULL) | |
824 | { | |
825 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", | |
826 | encryption_algorithm_names, enc_alg); | |
827 | return FAILED; | |
828 | } | |
829 | DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", | |
830 | encryption_algorithm_names, enc_alg, enc_size); | |
831 | ||
832 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_size / 8); | |
833 | hdr->nlmsg_len += rthdr->rta_len; | |
834 | if (hdr->nlmsg_len > sizeof(request)) | |
835 | { | |
836 | return FAILED; | |
837 | } | |
838 | ||
839 | struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); | |
840 | algo->alg_key_len = enc_size; | |
841 | strcpy(algo->alg_name, alg_name); | |
842 | prf_plus->get_bytes(prf_plus, enc_size / 8, algo->alg_key); | |
843 | ||
844 | rthdr = XFRM_RTA_NEXT(rthdr); | |
845 | break; | |
846 | } | |
847 | } | |
848 | ||
849 | if (int_alg != AUTH_UNDEFINED) | |
850 | { | |
851 | rthdr->rta_type = XFRMA_ALG_AUTH; | |
852 | alg_name = lookup_algorithm(integrity_algs, int_alg, &int_size); | |
853 | if (alg_name == NULL) | |
854 | { | |
855 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", | |
856 | integrity_algorithm_names, int_alg); | |
857 | return FAILED; | |
858 | } | |
859 | DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", | |
860 | integrity_algorithm_names, int_alg, int_size); | |
861 | ||
862 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_size / 8); | |
863 | hdr->nlmsg_len += rthdr->rta_len; | |
864 | if (hdr->nlmsg_len > sizeof(request)) | |
865 | { | |
866 | return FAILED; | |
867 | } | |
868 | ||
869 | struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); | |
870 | algo->alg_key_len = int_size; | |
871 | strcpy(algo->alg_name, alg_name); | |
872 | prf_plus->get_bytes(prf_plus, int_size / 8, algo->alg_key); | |
873 | ||
874 | rthdr = XFRM_RTA_NEXT(rthdr); | |
875 | } | |
876 | ||
877 | if (ipcomp != IPCOMP_NONE) | |
878 | { | |
879 | rthdr->rta_type = XFRMA_ALG_COMP; | |
880 | alg_name = lookup_algorithm(compression_algs, ipcomp, NULL); | |
881 | if (alg_name == NULL) | |
882 | { | |
883 | DBG1(DBG_KNL, "algorithm %N not supported by kernel!", | |
884 | ipcomp_transform_names, ipcomp); | |
885 | return FAILED; | |
886 | } | |
887 | DBG2(DBG_KNL, " using compression algorithm %N", | |
888 | ipcomp_transform_names, ipcomp); | |
889 | ||
890 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo)); | |
891 | hdr->nlmsg_len += rthdr->rta_len; | |
892 | if (hdr->nlmsg_len > sizeof(request)) | |
893 | { | |
894 | return FAILED; | |
895 | } | |
896 | ||
897 | struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); | |
898 | algo->alg_key_len = 0; | |
899 | strcpy(algo->alg_name, alg_name); | |
900 | ||
901 | rthdr = XFRM_RTA_NEXT(rthdr); | |
902 | } | |
903 | ||
904 | if (encap) | |
905 | { | |
906 | rthdr->rta_type = XFRMA_ENCAP; | |
907 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); | |
908 | ||
909 | hdr->nlmsg_len += rthdr->rta_len; | |
910 | if (hdr->nlmsg_len > sizeof(request)) | |
911 | { | |
912 | return FAILED; | |
913 | } | |
914 | ||
915 | struct xfrm_encap_tmpl* tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); | |
916 | tmpl->encap_type = UDP_ENCAP_ESPINUDP; | |
917 | tmpl->encap_sport = htons(src->get_port(src)); | |
918 | tmpl->encap_dport = htons(dst->get_port(dst)); | |
919 | memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); | |
920 | /* encap_oa could probably be derived from the | |
921 | * traffic selectors [rfc4306, p39]. In the netlink kernel implementation | |
922 | * pluto does the same as we do here but it uses encap_oa in the | |
923 | * pfkey implementation. BUT as /usr/src/linux/net/key/af_key.c indicates | |
924 | * the kernel ignores it anyway | |
925 | * -> does that mean that NAT-T encap doesn't work in transport mode? | |
926 | * No. The reason the kernel ignores NAT-OA is that it recomputes | |
927 | * (or, rather, just ignores) the checksum. If packets pass | |
928 | * the IPsec checks it marks them "checksum ok" so OA isn't needed. */ | |
929 | rthdr = XFRM_RTA_NEXT(rthdr); | |
930 | } | |
931 | ||
932 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) | |
933 | { | |
934 | DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi)); | |
935 | return FAILED; | |
936 | } | |
937 | return SUCCESS; | |
938 | } | |
939 | ||
940 | /** | |
941 | * Get the replay state (i.e. sequence numbers) of an SA. | |
942 | */ | |
943 | static status_t get_replay_state(private_kernel_netlink_ipsec_t *this, | |
944 | u_int32_t spi, protocol_id_t protocol, host_t *dst, | |
945 | struct xfrm_replay_state *replay) | |
946 | { | |
947 | unsigned char request[NETLINK_BUFFER_SIZE]; | |
948 | struct nlmsghdr *hdr, *out = NULL; | |
949 | struct xfrm_aevent_id *out_aevent = NULL, *aevent_id; | |
950 | size_t len; | |
951 | struct rtattr *rta; | |
952 | size_t rtasize; | |
953 | ||
954 | memset(&request, 0, sizeof(request)); | |
955 | ||
956 | DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x", ntohl(spi)); | |
957 | ||
958 | hdr = (struct nlmsghdr*)request; | |
959 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
960 | hdr->nlmsg_type = XFRM_MSG_GETAE; | |
961 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | |
962 | ||
963 | aevent_id = (struct xfrm_aevent_id*)NLMSG_DATA(hdr); | |
964 | aevent_id->flags = XFRM_AE_RVAL; | |
965 | ||
966 | host2xfrm(dst, &aevent_id->sa_id.daddr); | |
967 | aevent_id->sa_id.spi = spi; | |
968 | aevent_id->sa_id.proto = proto_ike2kernel(protocol); | |
969 | aevent_id->sa_id.family = dst->get_family(dst); | |
970 | ||
971 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) | |
972 | { | |
973 | hdr = out; | |
974 | while (NLMSG_OK(hdr, len)) | |
975 | { | |
976 | switch (hdr->nlmsg_type) | |
977 | { | |
978 | case XFRM_MSG_NEWAE: | |
979 | { | |
980 | out_aevent = NLMSG_DATA(hdr); | |
981 | break; | |
982 | } | |
983 | case NLMSG_ERROR: | |
984 | { | |
985 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
986 | DBG1(DBG_KNL, "querying replay state from SAD entry failed: %s (%d)", | |
987 | strerror(-err->error), -err->error); | |
988 | break; | |
989 | } | |
990 | default: | |
991 | hdr = NLMSG_NEXT(hdr, len); | |
992 | continue; | |
993 | case NLMSG_DONE: | |
994 | break; | |
995 | } | |
996 | break; | |
997 | } | |
998 | } | |
999 | ||
1000 | if (out_aevent == NULL) | |
1001 | { | |
1002 | DBG1(DBG_KNL, "unable to query replay state from SAD entry with SPI %.8x", | |
1003 | ntohl(spi)); | |
1004 | free(out); | |
1005 | return FAILED; | |
1006 | } | |
1007 | ||
1008 | rta = XFRM_RTA(out, struct xfrm_aevent_id); | |
1009 | rtasize = XFRM_PAYLOAD(out, struct xfrm_aevent_id); | |
1010 | while(RTA_OK(rta, rtasize)) | |
1011 | { | |
1012 | if (rta->rta_type == XFRMA_REPLAY_VAL) | |
1013 | { | |
1014 | memcpy(replay, RTA_DATA(rta), rta->rta_len); | |
1015 | free(out); | |
1016 | return SUCCESS; | |
1017 | } | |
1018 | rta = RTA_NEXT(rta, rtasize); | |
1019 | } | |
1020 | ||
1021 | DBG1(DBG_KNL, "unable to query replay state from SAD entry with SPI %.8x", | |
1022 | ntohl(spi)); | |
1023 | free(out); | |
1024 | return FAILED; | |
1025 | } | |
1026 | ||
1027 | /** | |
1028 | * Implementation of kernel_interface_t.update_sa. | |
1029 | */ | |
1030 | static status_t update_sa(private_kernel_netlink_ipsec_t *this, | |
1031 | u_int32_t spi, protocol_id_t protocol, | |
1032 | host_t *src, host_t *dst, | |
1033 | host_t *new_src, host_t *new_dst, bool encap) | |
1034 | { | |
1035 | unsigned char request[NETLINK_BUFFER_SIZE], *pos; | |
1036 | struct nlmsghdr *hdr, *out = NULL; | |
1037 | struct xfrm_usersa_id *sa_id; | |
1038 | struct xfrm_usersa_info *out_sa = NULL, *sa; | |
1039 | size_t len; | |
1040 | struct rtattr *rta; | |
1041 | size_t rtasize; | |
1042 | struct xfrm_encap_tmpl* tmpl = NULL; | |
1043 | bool got_replay_state; | |
1044 | struct xfrm_replay_state replay; | |
1045 | ||
1046 | memset(&request, 0, sizeof(request)); | |
1047 | ||
1048 | DBG2(DBG_KNL, "querying SAD entry with SPI %.8x for update", ntohl(spi)); | |
1049 | ||
1050 | /* query the existing SA first */ | |
1051 | hdr = (struct nlmsghdr*)request; | |
1052 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
1053 | hdr->nlmsg_type = XFRM_MSG_GETSA; | |
1054 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); | |
1055 | ||
1056 | sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); | |
1057 | host2xfrm(dst, &sa_id->daddr); | |
1058 | sa_id->spi = spi; | |
1059 | sa_id->proto = proto_ike2kernel(protocol); | |
1060 | sa_id->family = dst->get_family(dst); | |
1061 | ||
1062 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) | |
1063 | { | |
1064 | hdr = out; | |
1065 | while (NLMSG_OK(hdr, len)) | |
1066 | { | |
1067 | switch (hdr->nlmsg_type) | |
1068 | { | |
1069 | case XFRM_MSG_NEWSA: | |
1070 | { | |
1071 | out_sa = NLMSG_DATA(hdr); | |
1072 | break; | |
1073 | } | |
1074 | case NLMSG_ERROR: | |
1075 | { | |
1076 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
1077 | DBG1(DBG_KNL, "querying SAD entry failed: %s (%d)", | |
1078 | strerror(-err->error), -err->error); | |
1079 | break; | |
1080 | } | |
1081 | default: | |
1082 | hdr = NLMSG_NEXT(hdr, len); | |
1083 | continue; | |
1084 | case NLMSG_DONE: | |
1085 | break; | |
1086 | } | |
1087 | break; | |
1088 | } | |
1089 | } | |
1090 | if (out_sa == NULL) | |
1091 | { | |
1092 | DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi)); | |
1093 | free(out); | |
1094 | return FAILED; | |
1095 | } | |
1096 | ||
1097 | /* try to get the replay state */ | |
1098 | got_replay_state = (get_replay_state( | |
1099 | this, spi, protocol, dst, &replay) == SUCCESS); | |
1100 | ||
1101 | /* delete the old SA */ | |
1102 | if (this->public.interface.del_sa(&this->public.interface, dst, spi, protocol) != SUCCESS) | |
1103 | { | |
1104 | DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", ntohl(spi)); | |
1105 | free(out); | |
1106 | return FAILED; | |
1107 | } | |
1108 | ||
1109 | DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", | |
1110 | ntohl(spi), src, dst, new_src, new_dst); | |
1111 | ||
1112 | /* copy over the SA from out to request */ | |
1113 | hdr = (struct nlmsghdr*)request; | |
1114 | memcpy(hdr, out, min(out->nlmsg_len, sizeof(request))); | |
1115 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
1116 | hdr->nlmsg_type = XFRM_MSG_NEWSA; | |
1117 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); | |
1118 | sa = NLMSG_DATA(hdr); | |
1119 | sa->family = new_dst->get_family(new_dst); | |
1120 | ||
1121 | if (!src->ip_equals(src, new_src)) | |
1122 | { | |
1123 | host2xfrm(new_src, &sa->saddr); | |
1124 | } | |
1125 | if (!dst->ip_equals(dst, new_dst)) | |
1126 | { | |
1127 | host2xfrm(new_dst, &sa->id.daddr); | |
1128 | } | |
1129 | ||
1130 | rta = XFRM_RTA(out, struct xfrm_usersa_info); | |
1131 | rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info); | |
1132 | pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info); | |
1133 | while(RTA_OK(rta, rtasize)) | |
1134 | { | |
1135 | /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ | |
1136 | if (rta->rta_type != XFRMA_ENCAP || encap) | |
1137 | { | |
1138 | if (rta->rta_type == XFRMA_ENCAP) | |
1139 | { /* update encap tmpl */ | |
1140 | tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); | |
1141 | tmpl->encap_sport = ntohs(new_src->get_port(new_src)); | |
1142 | tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); | |
1143 | } | |
1144 | memcpy(pos, rta, rta->rta_len); | |
1145 | pos += RTA_ALIGN(rta->rta_len); | |
1146 | hdr->nlmsg_len += RTA_ALIGN(rta->rta_len); | |
1147 | } | |
1148 | rta = RTA_NEXT(rta, rtasize); | |
1149 | } | |
1150 | ||
1151 | rta = (struct rtattr*)pos; | |
1152 | if (tmpl == NULL && encap) | |
1153 | { /* add tmpl if we are enabling it */ | |
1154 | rta->rta_type = XFRMA_ENCAP; | |
1155 | rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); | |
1156 | ||
1157 | hdr->nlmsg_len += rta->rta_len; | |
1158 | if (hdr->nlmsg_len > sizeof(request)) | |
1159 | { | |
1160 | return FAILED; | |
1161 | } | |
1162 | ||
1163 | tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); | |
1164 | tmpl->encap_type = UDP_ENCAP_ESPINUDP; | |
1165 | tmpl->encap_sport = ntohs(new_src->get_port(new_src)); | |
1166 | tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); | |
1167 | memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); | |
1168 | ||
1169 | rta = XFRM_RTA_NEXT(rta); | |
1170 | } | |
1171 | ||
1172 | if (got_replay_state) | |
1173 | { /* copy the replay data if available */ | |
1174 | rta->rta_type = XFRMA_REPLAY_VAL; | |
1175 | rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state)); | |
1176 | ||
1177 | hdr->nlmsg_len += rta->rta_len; | |
1178 | if (hdr->nlmsg_len > sizeof(request)) | |
1179 | { | |
1180 | return FAILED; | |
1181 | } | |
1182 | memcpy(RTA_DATA(rta), &replay, sizeof(replay)); | |
1183 | ||
1184 | rta = XFRM_RTA_NEXT(rta); | |
1185 | } | |
1186 | ||
1187 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) | |
1188 | { | |
1189 | DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi)); | |
1190 | free(out); | |
1191 | return FAILED; | |
1192 | } | |
1193 | free(out); | |
1194 | ||
1195 | return SUCCESS; | |
1196 | } | |
1197 | ||
1198 | /** | |
1199 | * Implementation of kernel_interface_t.query_sa. | |
1200 | */ | |
1201 | static status_t query_sa(private_kernel_netlink_ipsec_t *this, host_t *dst, | |
1202 | u_int32_t spi, protocol_id_t protocol, | |
1203 | u_int32_t *use_time) | |
1204 | { | |
1205 | unsigned char request[NETLINK_BUFFER_SIZE]; | |
1206 | struct nlmsghdr *out = NULL, *hdr; | |
1207 | struct xfrm_usersa_id *sa_id; | |
1208 | struct xfrm_usersa_info *sa = NULL; | |
1209 | size_t len; | |
1210 | ||
1211 | DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi)); | |
1212 | memset(&request, 0, sizeof(request)); | |
1213 | ||
1214 | hdr = (struct nlmsghdr*)request; | |
1215 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
1216 | hdr->nlmsg_type = XFRM_MSG_GETSA; | |
1217 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); | |
1218 | ||
1219 | sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); | |
1220 | host2xfrm(dst, &sa_id->daddr); | |
1221 | sa_id->spi = spi; | |
1222 | sa_id->proto = proto_ike2kernel(protocol); | |
1223 | sa_id->family = dst->get_family(dst); | |
1224 | ||
1225 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) | |
1226 | { | |
1227 | hdr = out; | |
1228 | while (NLMSG_OK(hdr, len)) | |
1229 | { | |
1230 | switch (hdr->nlmsg_type) | |
1231 | { | |
1232 | case XFRM_MSG_NEWSA: | |
1233 | { | |
1234 | sa = NLMSG_DATA(hdr); | |
1235 | break; | |
1236 | } | |
1237 | case NLMSG_ERROR: | |
1238 | { | |
1239 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
1240 | DBG1(DBG_KNL, "querying SAD entry failed: %s (%d)", | |
1241 | strerror(-err->error), -err->error); | |
1242 | break; | |
1243 | } | |
1244 | default: | |
1245 | hdr = NLMSG_NEXT(hdr, len); | |
1246 | continue; | |
1247 | case NLMSG_DONE: | |
1248 | break; | |
1249 | } | |
1250 | break; | |
1251 | } | |
1252 | } | |
1253 | ||
1254 | if (sa == NULL) | |
1255 | { | |
1256 | DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi)); | |
1257 | free(out); | |
1258 | return FAILED; | |
1259 | } | |
1260 | ||
1261 | *use_time = sa->curlft.use_time; | |
1262 | free (out); | |
1263 | return SUCCESS; | |
1264 | } | |
1265 | ||
1266 | /** | |
1267 | * Implementation of kernel_interface_t.del_sa. | |
1268 | */ | |
1269 | static status_t del_sa(private_kernel_netlink_ipsec_t *this, host_t *dst, | |
1270 | u_int32_t spi, protocol_id_t protocol) | |
1271 | { | |
1272 | unsigned char request[NETLINK_BUFFER_SIZE]; | |
1273 | struct nlmsghdr *hdr; | |
1274 | struct xfrm_usersa_id *sa_id; | |
1275 | ||
1276 | memset(&request, 0, sizeof(request)); | |
1277 | ||
1278 | DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi)); | |
1279 | ||
1280 | hdr = (struct nlmsghdr*)request; | |
1281 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
1282 | hdr->nlmsg_type = XFRM_MSG_DELSA; | |
1283 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); | |
1284 | ||
1285 | sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); | |
1286 | host2xfrm(dst, &sa_id->daddr); | |
1287 | sa_id->spi = spi; | |
1288 | sa_id->proto = proto_ike2kernel(protocol); | |
1289 | sa_id->family = dst->get_family(dst); | |
1290 | ||
1291 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) | |
1292 | { | |
1293 | DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi)); | |
1294 | return FAILED; | |
1295 | } | |
1296 | DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi)); | |
1297 | return SUCCESS; | |
1298 | } | |
1299 | ||
1300 | /** | |
1301 | * Implementation of kernel_interface_t.add_policy. | |
1302 | */ | |
1303 | static status_t add_policy(private_kernel_netlink_ipsec_t *this, | |
1304 | host_t *src, host_t *dst, | |
1305 | traffic_selector_t *src_ts, | |
1306 | traffic_selector_t *dst_ts, | |
1307 | policy_dir_t direction, protocol_id_t protocol, | |
1308 | u_int32_t reqid, bool high_prio, mode_t mode, | |
1309 | u_int16_t ipcomp) | |
1310 | { | |
1311 | iterator_t *iterator; | |
1312 | policy_entry_t *current, *policy; | |
1313 | bool found = FALSE; | |
1314 | unsigned char request[NETLINK_BUFFER_SIZE]; | |
1315 | struct xfrm_userpolicy_info *policy_info; | |
1316 | struct nlmsghdr *hdr; | |
1317 | ||
1318 | /* create a policy */ | |
1319 | policy = malloc_thing(policy_entry_t); | |
1320 | memset(policy, 0, sizeof(policy_entry_t)); | |
1321 | policy->sel = ts2selector(src_ts, dst_ts); | |
1322 | policy->direction = direction; | |
1323 | ||
1324 | /* find the policy, which matches EXACTLY */ | |
1325 | pthread_mutex_lock(&this->mutex); | |
1326 | iterator = this->policies->create_iterator(this->policies, TRUE); | |
1327 | while (iterator->iterate(iterator, (void**)¤t)) | |
1328 | { | |
1329 | if (memeq(¤t->sel, &policy->sel, sizeof(struct xfrm_selector)) && | |
1330 | policy->direction == current->direction) | |
1331 | { | |
1332 | /* use existing policy */ | |
1333 | current->refcount++; | |
1334 | DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " | |
1335 | "refcount", src_ts, dst_ts, | |
1336 | policy_dir_names, direction); | |
1337 | free(policy); | |
1338 | policy = current; | |
1339 | found = TRUE; | |
1340 | break; | |
1341 | } | |
1342 | } | |
1343 | iterator->destroy(iterator); | |
1344 | if (!found) | |
1345 | { /* apply the new one, if we have no such policy */ | |
1346 | this->policies->insert_last(this->policies, policy); | |
1347 | policy->refcount = 1; | |
1348 | } | |
1349 | ||
1350 | DBG2(DBG_KNL, "adding policy %R === %R %N", src_ts, dst_ts, | |
1351 | policy_dir_names, direction); | |
1352 | ||
1353 | memset(&request, 0, sizeof(request)); | |
1354 | hdr = (struct nlmsghdr*)request; | |
1355 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
1356 | hdr->nlmsg_type = found ? XFRM_MSG_UPDPOLICY : XFRM_MSG_NEWPOLICY; | |
1357 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)); | |
1358 | ||
1359 | policy_info = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr); | |
1360 | policy_info->sel = policy->sel; | |
1361 | policy_info->dir = policy->direction; | |
1362 | /* calculate priority based on source selector size, small size = high prio */ | |
1363 | policy_info->priority = high_prio ? PRIO_HIGH : PRIO_LOW; | |
1364 | policy_info->priority -= policy->sel.prefixlen_s * 10; | |
1365 | policy_info->priority -= policy->sel.proto ? 2 : 0; | |
1366 | policy_info->priority -= policy->sel.sport_mask ? 1 : 0; | |
1367 | policy_info->action = XFRM_POLICY_ALLOW; | |
1368 | policy_info->share = XFRM_SHARE_ANY; | |
1369 | pthread_mutex_unlock(&this->mutex); | |
1370 | ||
1371 | /* policies don't expire */ | |
1372 | policy_info->lft.soft_byte_limit = XFRM_INF; | |
1373 | policy_info->lft.soft_packet_limit = XFRM_INF; | |
1374 | policy_info->lft.hard_byte_limit = XFRM_INF; | |
1375 | policy_info->lft.hard_packet_limit = XFRM_INF; | |
1376 | policy_info->lft.soft_add_expires_seconds = 0; | |
1377 | policy_info->lft.hard_add_expires_seconds = 0; | |
1378 | policy_info->lft.soft_use_expires_seconds = 0; | |
1379 | policy_info->lft.hard_use_expires_seconds = 0; | |
1380 | ||
1381 | struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info); | |
1382 | rthdr->rta_type = XFRMA_TMPL; | |
1383 | rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); | |
1384 | ||
1385 | hdr->nlmsg_len += rthdr->rta_len; | |
1386 | if (hdr->nlmsg_len > sizeof(request)) | |
1387 | { | |
1388 | return FAILED; | |
1389 | } | |
1390 | ||
1391 | struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr); | |
1392 | ||
1393 | if (ipcomp != IPCOMP_NONE) | |
1394 | { | |
1395 | tmpl->reqid = reqid; | |
1396 | tmpl->id.proto = IPPROTO_COMP; | |
1397 | tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; | |
1398 | tmpl->mode = mode; | |
1399 | tmpl->optional = direction != POLICY_OUT; | |
1400 | tmpl->family = src->get_family(src); | |
1401 | ||
1402 | host2xfrm(src, &tmpl->saddr); | |
1403 | host2xfrm(dst, &tmpl->id.daddr); | |
1404 | ||
1405 | /* add an additional xfrm_user_tmpl */ | |
1406 | rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); | |
1407 | hdr->nlmsg_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); | |
1408 | if (hdr->nlmsg_len > sizeof(request)) | |
1409 | { | |
1410 | return FAILED; | |
1411 | } | |
1412 | ||
1413 | tmpl++; | |
1414 | } | |
1415 | ||
1416 | tmpl->reqid = reqid; | |
1417 | tmpl->id.proto = proto_ike2kernel(protocol); | |
1418 | tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; | |
1419 | tmpl->mode = mode; | |
1420 | tmpl->family = src->get_family(src); | |
1421 | ||
1422 | host2xfrm(src, &tmpl->saddr); | |
1423 | host2xfrm(dst, &tmpl->id.daddr); | |
1424 | ||
1425 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) | |
1426 | { | |
1427 | DBG1(DBG_KNL, "unable to add policy %R === %R %N", src_ts, dst_ts, | |
1428 | policy_dir_names, direction); | |
1429 | return FAILED; | |
1430 | } | |
1431 | ||
1432 | /* install a route, if: | |
1433 | * - we are NOT updating a policy | |
1434 | * - this is a forward policy (to just get one for each child) | |
1435 | * - we are in tunnel mode | |
1436 | * - we are not using IPv6 (does not work correctly yet!) | |
1437 | * - routing is not disabled via strongswan.conf | |
1438 | */ | |
1439 | if (policy->route == NULL && direction == POLICY_FWD && | |
1440 | mode != MODE_TRANSPORT && src->get_family(src) != AF_INET6 && | |
1441 | this->install_routes) | |
1442 | { | |
1443 | route_entry_t *route = malloc_thing(route_entry_t); | |
1444 | ||
1445 | if (get_address_by_ts(this, dst_ts, &route->src_ip) == SUCCESS) | |
1446 | { | |
1447 | /* get the nexthop to src (src as we are in POLICY_FWD).*/ | |
1448 | route->gateway = charon->kernel_interface->get_nexthop( | |
1449 | charon->kernel_interface, src); | |
1450 | route->if_name = charon->kernel_interface->get_interface( | |
1451 | charon->kernel_interface, dst); | |
1452 | route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); | |
1453 | memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len); | |
1454 | route->prefixlen = policy->sel.prefixlen_s; | |
1455 | ||
1456 | switch (charon->kernel_interface->add_route(charon->kernel_interface, | |
1457 | route->dst_net, route->prefixlen, route->gateway, | |
1458 | route->src_ip, route->if_name)) | |
1459 | { | |
1460 | default: | |
1461 | DBG1(DBG_KNL, "unable to install source route for %H", | |
1462 | route->src_ip); | |
1463 | /* FALL */ | |
1464 | case ALREADY_DONE: | |
1465 | /* route exists, do not uninstall */ | |
1466 | route_entry_destroy(route); | |
1467 | break; | |
1468 | case SUCCESS: | |
1469 | /* cache the installed route */ | |
1470 | policy->route = route; | |
1471 | break; | |
1472 | } | |
1473 | } | |
1474 | else | |
1475 | { | |
1476 | free(route); | |
1477 | } | |
1478 | } | |
1479 | ||
1480 | return SUCCESS; | |
1481 | } | |
1482 | ||
1483 | /** | |
1484 | * Implementation of kernel_interface_t.query_policy. | |
1485 | */ | |
1486 | static status_t query_policy(private_kernel_netlink_ipsec_t *this, | |
1487 | traffic_selector_t *src_ts, | |
1488 | traffic_selector_t *dst_ts, | |
1489 | policy_dir_t direction, u_int32_t *use_time) | |
1490 | { | |
1491 | unsigned char request[NETLINK_BUFFER_SIZE]; | |
1492 | struct nlmsghdr *out = NULL, *hdr; | |
1493 | struct xfrm_userpolicy_id *policy_id; | |
1494 | struct xfrm_userpolicy_info *policy = NULL; | |
1495 | size_t len; | |
1496 | ||
1497 | memset(&request, 0, sizeof(request)); | |
1498 | ||
1499 | DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts, | |
1500 | policy_dir_names, direction); | |
1501 | ||
1502 | hdr = (struct nlmsghdr*)request; | |
1503 | hdr->nlmsg_flags = NLM_F_REQUEST; | |
1504 | hdr->nlmsg_type = XFRM_MSG_GETPOLICY; | |
1505 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)); | |
1506 | ||
1507 | policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr); | |
1508 | policy_id->sel = ts2selector(src_ts, dst_ts); | |
1509 | policy_id->dir = direction; | |
1510 | ||
1511 | if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) | |
1512 | { | |
1513 | hdr = out; | |
1514 | while (NLMSG_OK(hdr, len)) | |
1515 | { | |
1516 | switch (hdr->nlmsg_type) | |
1517 | { | |
1518 | case XFRM_MSG_NEWPOLICY: | |
1519 | { | |
1520 | policy = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr); | |
1521 | break; | |
1522 | } | |
1523 | case NLMSG_ERROR: | |
1524 | { | |
1525 | struct nlmsgerr *err = NLMSG_DATA(hdr); | |
1526 | DBG1(DBG_KNL, "querying policy failed: %s (%d)", | |
1527 | strerror(-err->error), -err->error); | |
1528 | break; | |
1529 | } | |
1530 | default: | |
1531 | hdr = NLMSG_NEXT(hdr, len); | |
1532 | continue; | |
1533 | case NLMSG_DONE: | |
1534 | break; | |
1535 | } | |
1536 | break; | |
1537 | } | |
1538 | } | |
1539 | ||
1540 | if (policy == NULL) | |
1541 | { | |
1542 | DBG2(DBG_KNL, "unable to query policy %R === %R %N", src_ts, dst_ts, | |
1543 | policy_dir_names, direction); | |
1544 | free(out); | |
1545 | return FAILED; | |
1546 | } | |
1547 | *use_time = (time_t)policy->curlft.use_time; | |
1548 | ||
1549 | free(out); | |
1550 | return SUCCESS; | |
1551 | } | |
1552 | ||
1553 | /** | |
1554 | * Implementation of kernel_interface_t.del_policy. | |
1555 | */ | |
1556 | static status_t del_policy(private_kernel_netlink_ipsec_t *this, | |
1557 | traffic_selector_t *src_ts, | |
1558 | traffic_selector_t *dst_ts, | |
1559 | policy_dir_t direction) | |
1560 | { | |
1561 | policy_entry_t *current, policy, *to_delete = NULL; | |
1562 | route_entry_t *route; | |
1563 | unsigned char request[NETLINK_BUFFER_SIZE]; | |
1564 | struct nlmsghdr *hdr; | |
1565 | struct xfrm_userpolicy_id *policy_id; | |
1566 | iterator_t *iterator; | |
1567 | ||
1568 | DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts, | |
1569 | policy_dir_names, direction); | |
1570 | ||
1571 | /* create a policy */ | |
1572 | memset(&policy, 0, sizeof(policy_entry_t)); | |
1573 | policy.sel = ts2selector(src_ts, dst_ts); | |
1574 | policy.direction = direction; | |
1575 | ||
1576 | /* find the policy */ | |
1577 | iterator = this->policies->create_iterator_locked(this->policies, &this->mutex); | |
1578 | while (iterator->iterate(iterator, (void**)¤t)) | |
1579 | { | |
1580 | if (memcmp(¤t->sel, &policy.sel, sizeof(struct xfrm_selector)) == 0 && | |
1581 | policy.direction == current->direction) | |
1582 | { | |
1583 | to_delete = current; | |
1584 | if (--to_delete->refcount > 0) | |
1585 | { | |
1586 | /* is used by more SAs, keep in kernel */ | |
1587 | DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); | |
1588 | iterator->destroy(iterator); | |
1589 | return SUCCESS; | |
1590 | } | |
1591 | /* remove if last reference */ | |
1592 | iterator->remove(iterator); | |
1593 | break; | |
1594 | } | |
1595 | } | |
1596 | iterator->destroy(iterator); | |
1597 | if (!to_delete) | |
1598 | { | |
1599 | DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts, | |
1600 | dst_ts, policy_dir_names, direction); | |
1601 | return NOT_FOUND; | |
1602 | } | |
1603 | ||
1604 | memset(&request, 0, sizeof(request)); | |
1605 | ||
1606 | hdr = (struct nlmsghdr*)request; | |
1607 | hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
1608 | hdr->nlmsg_type = XFRM_MSG_DELPOLICY; | |
1609 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)); | |
1610 | ||
1611 | policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr); | |
1612 | policy_id->sel = to_delete->sel; | |
1613 | policy_id->dir = direction; | |
1614 | ||
1615 | route = to_delete->route; | |
1616 | free(to_delete); | |
1617 | ||
1618 | if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) | |
1619 | { | |
1620 | DBG1(DBG_KNL, "unable to delete policy %R === %R %N", src_ts, dst_ts, | |
1621 | policy_dir_names, direction); | |
1622 | return FAILED; | |
1623 | } | |
1624 | ||
1625 | if (route) | |
1626 | { | |
1627 | if (charon->kernel_interface->del_route(charon->kernel_interface, | |
1628 | route->dst_net, route->prefixlen, route->gateway, | |
1629 | route->src_ip, route->if_name) != SUCCESS) | |
1630 | { | |
1631 | DBG1(DBG_KNL, "error uninstalling route installed with " | |
1632 | "policy %R === %R %N", src_ts, dst_ts, | |
1633 | policy_dir_names, direction); | |
1634 | } | |
1635 | route_entry_destroy(route); | |
1636 | } | |
1637 | return SUCCESS; | |
1638 | } | |
1639 | ||
1640 | /** | |
1641 | * Implementation of kernel_interface_t.destroy. | |
1642 | */ | |
1643 | static void destroy(private_kernel_netlink_ipsec_t *this) | |
1644 | { | |
1645 | this->job->cancel(this->job); | |
1646 | close(this->socket_xfrm_events); | |
1647 | this->socket_xfrm->destroy(this->socket_xfrm); | |
1648 | this->policies->destroy(this->policies); | |
1649 | free(this); | |
1650 | } | |
1651 | ||
1652 | /* | |
1653 | * Described in header. | |
1654 | */ | |
1655 | kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() | |
1656 | { | |
1657 | private_kernel_netlink_ipsec_t *this = malloc_thing(private_kernel_netlink_ipsec_t); | |
1658 | struct sockaddr_nl addr; | |
1659 | ||
1660 | /* public functions */ | |
1661 | 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; | |
1662 | this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi; | |
1663 | this->public.interface.add_sa = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,mode_t,u_int16_t,bool,bool))add_sa; | |
1664 | this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa; | |
1665 | this->public.interface.query_sa = (status_t(*)(kernel_ipsec_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa; | |
1666 | this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,u_int32_t,protocol_id_t))del_sa; | |
1667 | this->public.interface.add_policy = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t,u_int16_t))add_policy; | |
1668 | this->public.interface.query_policy = (status_t(*)(kernel_ipsec_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy; | |
1669 | this->public.interface.del_policy = (status_t(*)(kernel_ipsec_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy; | |
1670 | this->public.interface.destroy = (void(*)(kernel_ipsec_t*)) destroy; | |
1671 | ||
1672 | /* private members */ | |
1673 | this->policies = linked_list_create(); | |
1674 | pthread_mutex_init(&this->mutex, NULL); | |
1675 | this->install_routes = lib->settings->get_bool(lib->settings, | |
1676 | "charon.install_routes", TRUE); | |
1677 | ||
1678 | this->socket_xfrm = netlink_socket_create(NETLINK_XFRM); | |
1679 | ||
1680 | memset(&addr, 0, sizeof(addr)); | |
1681 | addr.nl_family = AF_NETLINK; | |
1682 | ||
1683 | /* create and bind XFRM socket for ACQUIRE & EXPIRE */ | |
1684 | this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); | |
1685 | if (this->socket_xfrm_events <= 0) | |
1686 | { | |
1687 | charon->kill(charon, "unable to create XFRM event socket"); | |
1688 | } | |
1689 | addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; | |
1690 | if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr))) | |
1691 | { | |
1692 | charon->kill(charon, "unable to bind XFRM event socket"); | |
1693 | } | |
1694 | ||
1695 | this->job = callback_job_create((callback_job_cb_t)receive_events, | |
1696 | this, NULL, NULL); | |
1697 | charon->processor->queue_job(charon->processor, (job_t*)this->job); | |
1698 | ||
1699 | return &this->public; | |
1700 | } |