cf85cb0a6e3087c64bc8332d568ac335b2cca0dd
[strongswan.git] / src / libcharon / plugins / kernel_netlink / kernel_netlink_shared.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
4 * Copyright (C) 2008 Tobias Brunner
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 /*
19 * Copyright (C) 2016 secunet Security Networks AG
20 * Copyright (C) 2016 Thomas Egerer
21 *
22 * Permission is hereby granted, free of charge, to any person obtaining a copy
23 * of this software and associated documentation files (the "Software"), to deal
24 * in the Software without restriction, including without limitation the rights
25 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26 * copies of the Software, and to permit persons to whom the Software is
27 * furnished to do so, subject to the following conditions:
28 *
29 * The above copyright notice and this permission notice shall be included in
30 * all copies or substantial portions of the Software.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38 * THE SOFTWARE.
39 */
40
41 #include <sys/socket.h>
42 #include <linux/netlink.h>
43 #include <linux/rtnetlink.h>
44 #include <linux/xfrm.h>
45 #include <errno.h>
46 #include <unistd.h>
47
48 #include "kernel_netlink_shared.h"
49
50 #include <utils/debug.h>
51 #include <threading/mutex.h>
52 #include <threading/condvar.h>
53 #include <collections/array.h>
54 #include <collections/hashtable.h>
55
56 typedef struct private_netlink_socket_t private_netlink_socket_t;
57
58 /**
59 * Private variables and functions of netlink_socket_t class.
60 */
61 struct private_netlink_socket_t {
62
63 /**
64 * public part of the netlink_socket_t object.
65 */
66 netlink_socket_t public;
67
68 /**
69 * mutex to lock access entries
70 */
71 mutex_t *mutex;
72
73 /**
74 * Netlink request entries currently active, uintptr_t seq => entry_t
75 */
76 hashtable_t *entries;
77
78 /**
79 * Current sequence number for Netlink requests
80 */
81 refcount_t seq;
82
83 /**
84 * netlink socket
85 */
86 int socket;
87
88 /**
89 * Netlink protocol
90 */
91 int protocol;
92
93 /**
94 * Enum names for Netlink messages
95 */
96 enum_name_t *names;
97
98 /**
99 * Timeout for Netlink replies, in ms
100 */
101 u_int timeout;
102
103 /**
104 * Number of times to repeat timed out queries
105 */
106 u_int retries;
107
108 /**
109 * Buffer size for received Netlink messages
110 */
111 u_int buflen;
112
113 /**
114 * Use parallel netlink queries
115 */
116 bool parallel;
117
118 /**
119 * Ignore errors potentially resulting from a retransmission
120 */
121 bool ignore_retransmit_errors;
122 };
123
124 /**
125 * #definable hook to simulate request message loss
126 */
127 #ifdef NETLINK_MSG_LOSS_HOOK
128 bool NETLINK_MSG_LOSS_HOOK(struct nlmsghdr *msg);
129 #define msg_loss_hook(msg) NETLINK_MSG_LOSS_HOOK(msg)
130 #else
131 #define msg_loss_hook(msg) FALSE
132 #endif
133
134 /**
135 * Request entry the answer for a waiting thread is collected in
136 */
137 typedef struct {
138 /** Condition variable thread is waiting */
139 condvar_t *condvar;
140 /** Array of hdrs in a multi-message response, as struct nlmsghdr* */
141 array_t *hdrs;
142 /** All response messages received? */
143 bool complete;
144 } entry_t;
145
146 /**
147 * Clean up a thread waiting entry
148 */
149 static void destroy_entry(entry_t *entry)
150 {
151 entry->condvar->destroy(entry->condvar);
152 array_destroy_function(entry->hdrs, (void*)free, NULL);
153 free(entry);
154 }
155
156 /**
157 * Write a Netlink message to socket
158 */
159 static bool write_msg(private_netlink_socket_t *this, struct nlmsghdr *msg)
160 {
161 struct sockaddr_nl addr = {
162 .nl_family = AF_NETLINK,
163 };
164 int len;
165
166 if (msg_loss_hook(msg))
167 {
168 return TRUE;
169 }
170
171 while (TRUE)
172 {
173 len = sendto(this->socket, msg, msg->nlmsg_len, 0,
174 (struct sockaddr*)&addr, sizeof(addr));
175 if (len != msg->nlmsg_len)
176 {
177 if (errno == EINTR)
178 {
179 continue;
180 }
181 DBG1(DBG_KNL, "netlink write error: %s", strerror(errno));
182 return FALSE;
183 }
184 return TRUE;
185 }
186 }
187
188 /**
189 * Read a single Netlink message from socket, return 0 on error, -1 on timeout
190 */
191 static ssize_t read_msg(private_netlink_socket_t *this,
192 char *buf, size_t buflen, bool block)
193 {
194 ssize_t len;
195
196 if (block)
197 {
198 fd_set set;
199 timeval_t tv = {};
200
201 FD_ZERO(&set);
202 FD_SET(this->socket, &set);
203 timeval_add_ms(&tv, this->timeout);
204
205 if (select(this->socket + 1, &set, NULL, NULL,
206 this->timeout ? &tv : NULL) <= 0)
207 {
208 return -1;
209 }
210 }
211 len = recv(this->socket, buf, buflen, MSG_TRUNC|(block ? 0 : MSG_DONTWAIT));
212 if (len > buflen)
213 {
214 DBG1(DBG_KNL, "netlink response exceeds buffer size");
215 return 0;
216 }
217 if (len < 0)
218 {
219 if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
220 {
221 DBG1(DBG_KNL, "netlink read error: %s", strerror(errno));
222 }
223 return 0;
224 }
225 return len;
226 }
227
228 /**
229 * Queue received response message
230 */
231 static bool queue(private_netlink_socket_t *this, struct nlmsghdr *buf)
232 {
233 struct nlmsghdr *hdr;
234 entry_t *entry;
235 uintptr_t seq;
236
237 seq = (uintptr_t)buf->nlmsg_seq;
238
239 this->mutex->lock(this->mutex);
240 entry = this->entries->get(this->entries, (void*)seq);
241 if (entry)
242 {
243 hdr = malloc(buf->nlmsg_len);
244 memcpy(hdr, buf, buf->nlmsg_len);
245 array_insert(entry->hdrs, ARRAY_TAIL, hdr);
246 if (hdr->nlmsg_type == NLMSG_DONE || !(hdr->nlmsg_flags & NLM_F_MULTI))
247 {
248 entry->complete = TRUE;
249 entry->condvar->signal(entry->condvar);
250 }
251 }
252 else
253 {
254 DBG1(DBG_KNL, "received unknown netlink seq %u, ignored", seq);
255 }
256 this->mutex->unlock(this->mutex);
257
258 return entry != NULL;
259 }
260
261 /**
262 * Read and queue response message, optionally blocking, returns TRUE on timeout
263 */
264 static bool read_and_queue(private_netlink_socket_t *this, bool block)
265 {
266 struct nlmsghdr *hdr;
267 char buf[this->buflen];
268 ssize_t len;
269
270 len = read_msg(this, buf, sizeof(buf), block);
271 if (len == -1)
272 {
273 return TRUE;
274 }
275 if (len)
276 {
277 hdr = (struct nlmsghdr*)buf;
278 while (NLMSG_OK(hdr, len))
279 {
280 if (!queue(this, hdr))
281 {
282 break;
283 }
284 hdr = NLMSG_NEXT(hdr, len);
285 }
286 }
287 return FALSE;
288 }
289
290 CALLBACK(watch, bool,
291 private_netlink_socket_t *this, int fd, watcher_event_t event)
292 {
293 if (event == WATCHER_READ)
294 {
295 read_and_queue(this, FALSE);
296 }
297 return TRUE;
298 }
299
300 /**
301 * Send a netlink request, try once
302 */
303 static status_t send_once(private_netlink_socket_t *this, struct nlmsghdr *in,
304 uintptr_t seq, struct nlmsghdr **out, size_t *out_len)
305 {
306 struct nlmsghdr *hdr;
307 entry_t *entry;
308 u_char *ptr;
309 int i;
310
311 in->nlmsg_seq = seq;
312 in->nlmsg_pid = getpid();
313
314 if (this->names)
315 {
316 DBG3(DBG_KNL, "sending %N %u: %b", this->names, in->nlmsg_type,
317 (u_int)seq, in, in->nlmsg_len);
318 }
319
320 this->mutex->lock(this->mutex);
321 if (!write_msg(this, in))
322 {
323 this->mutex->unlock(this->mutex);
324 return FAILED;
325 }
326
327 INIT(entry,
328 .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
329 .hdrs = array_create(0, 0),
330 );
331 this->entries->put(this->entries, (void*)seq, entry);
332
333 while (!entry->complete)
334 {
335 if (this->parallel &&
336 lib->watcher->get_state(lib->watcher) != WATCHER_STOPPED &&
337 lib->processor->get_total_threads(lib->processor))
338 {
339 if (this->timeout)
340 {
341 if (entry->condvar->timed_wait(entry->condvar, this->mutex,
342 this->timeout))
343 {
344 break;
345 }
346 }
347 else
348 {
349 entry->condvar->wait(entry->condvar, this->mutex);
350 }
351 }
352 else
353 { /* During (de-)initialization, no watcher thread is active.
354 * collect responses ourselves. */
355 if (read_and_queue(this, TRUE))
356 {
357 break;
358 }
359 }
360 }
361 this->entries->remove(this->entries, (void*)seq);
362
363 this->mutex->unlock(this->mutex);
364
365 if (!entry->complete)
366 { /* timeout */
367 destroy_entry(entry);
368 return OUT_OF_RES;
369 }
370
371 for (i = 0, *out_len = 0; i < array_count(entry->hdrs); i++)
372 {
373 array_get(entry->hdrs, i, &hdr);
374 *out_len += hdr->nlmsg_len;
375 }
376 ptr = malloc(*out_len);
377 *out = (struct nlmsghdr*)ptr;
378
379 while (array_remove(entry->hdrs, ARRAY_HEAD, &hdr))
380 {
381 if (this->names)
382 {
383 DBG3(DBG_KNL, "received %N %u: %b", this->names, hdr->nlmsg_type,
384 hdr->nlmsg_seq, hdr, hdr->nlmsg_len);
385 }
386 memcpy(ptr, hdr, hdr->nlmsg_len);
387 ptr += hdr->nlmsg_len;
388 free(hdr);
389 }
390 destroy_entry(entry);
391 return SUCCESS;
392 }
393
394 /**
395 * Ignore errors for message types that might have completed previously
396 */
397 static void ignore_retransmit_error(private_netlink_socket_t *this,
398 struct nlmsgerr *err, int type)
399 {
400 switch (err->error)
401 {
402 case -EEXIST:
403 switch (this->protocol)
404 {
405 case NETLINK_XFRM:
406 switch (type)
407 {
408 case XFRM_MSG_NEWPOLICY:
409 case XFRM_MSG_NEWSA:
410 err->error = 0;
411 break;
412 }
413 break;
414 case NETLINK_ROUTE:
415 switch (type)
416 {
417 case RTM_NEWADDR:
418 case RTM_NEWLINK:
419 case RTM_NEWNEIGH:
420 case RTM_NEWROUTE:
421 case RTM_NEWRULE:
422 err->error = 0;
423 break;
424 }
425 break;
426 }
427 break;
428 case -ENOENT:
429 switch (this->protocol)
430 {
431 case NETLINK_XFRM:
432 switch (type)
433 {
434 case XFRM_MSG_DELPOLICY:
435 case XFRM_MSG_DELSA:
436 err->error = 0;
437 break;
438 }
439 break;
440 case NETLINK_ROUTE:
441 switch (type)
442 {
443 case RTM_DELADDR:
444 case RTM_DELLINK:
445 case RTM_DELNEIGH:
446 case RTM_DELROUTE:
447 case RTM_DELRULE:
448 err->error = 0;
449 break;
450 }
451 break;
452 }
453 break;
454 }
455 }
456
457 METHOD(netlink_socket_t, netlink_send, status_t,
458 private_netlink_socket_t *this, struct nlmsghdr *in, struct nlmsghdr **out,
459 size_t *out_len)
460 {
461 uintptr_t seq;
462 u_int try;
463
464 seq = ref_get(&this->seq);
465
466 for (try = 0; try <= this->retries; ++try)
467 {
468 struct nlmsghdr *hdr;
469 status_t status;
470 size_t len;
471
472 if (try > 0)
473 {
474 DBG1(DBG_KNL, "retransmitting Netlink request (%u/%u)",
475 try, this->retries);
476 }
477 status = send_once(this, in, seq, &hdr, &len);
478 switch (status)
479 {
480 case SUCCESS:
481 break;
482 case OUT_OF_RES:
483 continue;
484 default:
485 return status;
486 }
487 if (hdr->nlmsg_type == NLMSG_ERROR)
488 {
489 struct nlmsgerr* err;
490
491 err = NLMSG_DATA(hdr);
492 if (err->error == -EBUSY)
493 {
494 free(hdr);
495 try--;
496 continue;
497 }
498 if (this->ignore_retransmit_errors && try > 0)
499 {
500 ignore_retransmit_error(this, err, in->nlmsg_type);
501 }
502 }
503 *out = hdr;
504 *out_len = len;
505 return SUCCESS;
506 }
507 DBG1(DBG_KNL, "Netlink request timed out after %u retransmits",
508 this->retries);
509 return OUT_OF_RES;
510 }
511
512 METHOD(netlink_socket_t, netlink_send_ack, status_t,
513 private_netlink_socket_t *this, struct nlmsghdr *in)
514 {
515 struct nlmsghdr *out, *hdr;
516 size_t len;
517
518 if (netlink_send(this, in, &out, &len) != SUCCESS)
519 {
520 return FAILED;
521 }
522 hdr = out;
523 while (NLMSG_OK(hdr, len))
524 {
525 switch (hdr->nlmsg_type)
526 {
527 case NLMSG_ERROR:
528 {
529 struct nlmsgerr* err = NLMSG_DATA(hdr);
530
531 if (err->error)
532 {
533 if (-err->error == EEXIST)
534 { /* do not report existing routes */
535 free(out);
536 return ALREADY_DONE;
537 }
538 if (-err->error == ESRCH)
539 { /* do not report missing entries */
540 free(out);
541 return NOT_FOUND;
542 }
543 DBG1(DBG_KNL, "received netlink error: %s (%d)",
544 strerror(-err->error), -err->error);
545 free(out);
546 return FAILED;
547 }
548 free(out);
549 return SUCCESS;
550 }
551 default:
552 hdr = NLMSG_NEXT(hdr, len);
553 continue;
554 case NLMSG_DONE:
555 break;
556 }
557 break;
558 }
559 DBG1(DBG_KNL, "netlink request not acknowledged");
560 free(out);
561 return FAILED;
562 }
563
564 METHOD(netlink_socket_t, destroy, void,
565 private_netlink_socket_t *this)
566 {
567 if (this->socket != -1)
568 {
569 if (this->parallel)
570 {
571 lib->watcher->remove(lib->watcher, this->socket);
572 }
573 close(this->socket);
574 }
575 this->entries->destroy(this->entries);
576 this->mutex->destroy(this->mutex);
577 free(this);
578 }
579
580 /**
581 * Described in header.
582 */
583 netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
584 bool parallel)
585 {
586 private_netlink_socket_t *this;
587 struct sockaddr_nl addr = {
588 .nl_family = AF_NETLINK,
589 };
590 bool force_buf = FALSE;
591 int rcvbuf_size = 0;
592
593 INIT(this,
594 .public = {
595 .send = _netlink_send,
596 .send_ack = _netlink_send_ack,
597 .destroy = _destroy,
598 },
599 .seq = 200,
600 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
601 .socket = socket(AF_NETLINK, SOCK_RAW, protocol),
602 .entries = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),
603 .protocol = protocol,
604 .names = names,
605 .buflen = lib->settings->get_int(lib->settings,
606 "%s.plugins.kernel-netlink.buflen", 0, lib->ns),
607 .timeout = lib->settings->get_int(lib->settings,
608 "%s.plugins.kernel-netlink.timeout", 0, lib->ns),
609 .retries = lib->settings->get_int(lib->settings,
610 "%s.plugins.kernel-netlink.retries", 0, lib->ns),
611 .ignore_retransmit_errors = lib->settings->get_bool(lib->settings,
612 "%s.plugins.kernel-netlink.ignore_retransmit_errors",
613 FALSE, lib->ns),
614 .parallel = parallel,
615 );
616
617 if (!this->buflen)
618 {
619 long pagesize = sysconf(_SC_PAGESIZE);
620 if (pagesize == -1)
621 {
622 pagesize = 4096;
623 }
624 /* base this on NLMSG_GOODSIZE */
625 this->buflen = min(pagesize, 8192);
626 }
627 if (this->socket == -1)
628 {
629 DBG1(DBG_KNL, "unable to create netlink socket: %s (%d)",
630 strerror(errno), errno);
631 destroy(this);
632 return NULL;
633 }
634 if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)))
635 {
636 DBG1(DBG_KNL, "unable to bind netlink socket: %s (%d)",
637 strerror(errno), errno);
638 destroy(this);
639 return NULL;
640 }
641 rcvbuf_size = lib->settings->get_int(lib->settings,
642 "%s.plugins.kernel-netlink.receive_buffer_size",
643 rcvbuf_size, lib->ns);
644 if (rcvbuf_size)
645 {
646 int optname;
647
648 force_buf = lib->settings->get_bool(lib->settings,
649 "%s.plugins.kernel-netlink.force_receive_buffer_size",
650 force_buf, lib->ns);
651 optname = force_buf ? SO_RCVBUFFORCE : SO_RCVBUF;
652
653 if (setsockopt(this->socket, SOL_SOCKET, optname, &rcvbuf_size,
654 sizeof(rcvbuf_size)) == -1)
655 {
656 DBG1(DBG_KNL, "failed to %supdate receive buffer size to %d: %s",
657 force_buf ? "forcibly " : "", rcvbuf_size, strerror(errno));
658 }
659 }
660 if (this->parallel)
661 {
662 lib->watcher->add(lib->watcher, this->socket, WATCHER_READ, watch, this);
663 }
664
665 return &this->public;
666 }
667
668 /**
669 * Described in header.
670 */
671 void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
672 size_t buflen)
673 {
674 struct rtattr *rta;
675
676 if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_LENGTH(data.len) > buflen)
677 {
678 DBG1(DBG_KNL, "unable to add attribute, buffer too small");
679 return;
680 }
681
682 rta = (struct rtattr*)(((char*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len));
683 rta->rta_type = rta_type;
684 rta->rta_len = RTA_LENGTH(data.len);
685 memcpy(RTA_DATA(rta), data.ptr, data.len);
686 hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
687 }
688
689 /**
690 * Described in header.
691 */
692 void* netlink_reserve(struct nlmsghdr *hdr, int buflen, int type, int len)
693 {
694 struct rtattr *rta;
695
696 if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_LENGTH(len) > buflen)
697 {
698 DBG1(DBG_KNL, "unable to add attribute, buffer too small");
699 return NULL;
700 }
701
702 rta = ((void*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len);
703 rta->rta_type = type;
704 rta->rta_len = RTA_LENGTH(len);
705 hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
706
707 return RTA_DATA(rta);
708 }