]> git.proxmox.com Git - mirror_iproute2.git/blob - lib/libnetlink.c
e28e1ab6da5e96fa65c9e0b8cc78a62a510f71be
[mirror_iproute2.git] / lib / libnetlink.c
1 /*
2 * libnetlink.c RTnetlink service routines.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdbool.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <net/if_arp.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <time.h>
24 #include <sys/uio.h>
25 #include <linux/fib_rules.h>
26 #include <linux/if_addrlabel.h>
27 #include <linux/if_bridge.h>
28
29 #include "libnetlink.h"
30
31 #ifndef SOL_NETLINK
32 #define SOL_NETLINK 270
33 #endif
34
35 #ifndef MIN
36 #define MIN(a, b) ((a) < (b) ? (a) : (b))
37 #endif
38
39 int rcvbuf = 1024 * 1024;
40
41 #ifdef HAVE_LIBMNL
42 #include <libmnl/libmnl.h>
43
44 static const enum mnl_attr_data_type extack_policy[NLMSGERR_ATTR_MAX + 1] = {
45 [NLMSGERR_ATTR_MSG] = MNL_TYPE_NUL_STRING,
46 [NLMSGERR_ATTR_OFFS] = MNL_TYPE_U32,
47 };
48
49 static int err_attr_cb(const struct nlattr *attr, void *data)
50 {
51 const struct nlattr **tb = data;
52 uint16_t type;
53
54 if (mnl_attr_type_valid(attr, NLMSGERR_ATTR_MAX) < 0) {
55 fprintf(stderr, "Invalid extack attribute\n");
56 return MNL_CB_ERROR;
57 }
58
59 type = mnl_attr_get_type(attr);
60 if (mnl_attr_validate(attr, extack_policy[type]) < 0) {
61 fprintf(stderr, "extack attribute %d failed validation\n",
62 type);
63 return MNL_CB_ERROR;
64 }
65
66 tb[type] = attr;
67 return MNL_CB_OK;
68 }
69
70 static void print_ext_ack_msg(bool is_err, const char *msg)
71 {
72 fprintf(stderr, "%s: %s", is_err ? "Error" : "Warning", msg);
73 if (msg[strlen(msg) - 1] != '.')
74 fprintf(stderr, ".");
75 fprintf(stderr, "\n");
76 }
77
78 /* dump netlink extended ack error message */
79 int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
80 {
81 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
82 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
83 const struct nlmsghdr *err_nlh = NULL;
84 unsigned int hlen = sizeof(*err);
85 const char *msg = NULL;
86 uint32_t off = 0;
87
88 /* no TLVs, nothing to do here */
89 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
90 return 0;
91
92 /* if NLM_F_CAPPED is set then the inner err msg was capped */
93 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
94 hlen += mnl_nlmsg_get_payload_len(&err->msg);
95
96 if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
97 return 0;
98
99 if (tb[NLMSGERR_ATTR_MSG])
100 msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
101
102 if (tb[NLMSGERR_ATTR_OFFS]) {
103 off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
104
105 if (off > nlh->nlmsg_len) {
106 fprintf(stderr,
107 "Invalid offset for NLMSGERR_ATTR_OFFS\n");
108 off = 0;
109 } else if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
110 err_nlh = &err->msg;
111 }
112
113 if (errfn)
114 return errfn(msg, off, err_nlh);
115
116 if (msg && *msg != '\0') {
117 bool is_err = !!err->error;
118
119 print_ext_ack_msg(is_err, msg);
120 return is_err ? 1 : 0;
121 }
122
123 return 0;
124 }
125
126 static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
127 {
128 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
129 unsigned int hlen = sizeof(int);
130 const char *msg = NULL;
131
132 if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
133 return 0;
134
135 if (tb[NLMSGERR_ATTR_MSG])
136 msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
137
138 if (msg && *msg != '\0') {
139 bool is_err = !!error;
140
141 print_ext_ack_msg(is_err, msg);
142 return is_err ? 1 : 0;
143 }
144
145 return 0;
146 }
147 #else
148 #warning "libmnl required for error support"
149
150 /* No extended error ack without libmnl */
151 int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
152 {
153 return 0;
154 }
155
156 static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
157 {
158 return 0;
159 }
160 #endif
161
162 void rtnl_close(struct rtnl_handle *rth)
163 {
164 if (rth->fd >= 0) {
165 close(rth->fd);
166 rth->fd = -1;
167 }
168 }
169
170 int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
171 int protocol)
172 {
173 socklen_t addr_len;
174 int sndbuf = 32768;
175 int one = 1;
176
177 memset(rth, 0, sizeof(*rth));
178
179 rth->proto = protocol;
180 rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
181 if (rth->fd < 0) {
182 perror("Cannot open netlink socket");
183 return -1;
184 }
185
186 if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF,
187 &sndbuf, sizeof(sndbuf)) < 0) {
188 perror("SO_SNDBUF");
189 return -1;
190 }
191
192 if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF,
193 &rcvbuf, sizeof(rcvbuf)) < 0) {
194 perror("SO_RCVBUF");
195 return -1;
196 }
197
198 /* Older kernels may no support extended ACK reporting */
199 setsockopt(rth->fd, SOL_NETLINK, NETLINK_EXT_ACK,
200 &one, sizeof(one));
201
202 memset(&rth->local, 0, sizeof(rth->local));
203 rth->local.nl_family = AF_NETLINK;
204 rth->local.nl_groups = subscriptions;
205
206 if (bind(rth->fd, (struct sockaddr *)&rth->local,
207 sizeof(rth->local)) < 0) {
208 perror("Cannot bind netlink socket");
209 return -1;
210 }
211 addr_len = sizeof(rth->local);
212 if (getsockname(rth->fd, (struct sockaddr *)&rth->local,
213 &addr_len) < 0) {
214 perror("Cannot getsockname");
215 return -1;
216 }
217 if (addr_len != sizeof(rth->local)) {
218 fprintf(stderr, "Wrong address length %d\n", addr_len);
219 return -1;
220 }
221 if (rth->local.nl_family != AF_NETLINK) {
222 fprintf(stderr, "Wrong address family %d\n",
223 rth->local.nl_family);
224 return -1;
225 }
226 rth->seq = time(NULL);
227 return 0;
228 }
229
230 int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
231 {
232 return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
233 }
234
235 int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
236 {
237 struct {
238 struct nlmsghdr nlh;
239 struct ifaddrmsg ifm;
240 } req = {
241 .nlh.nlmsg_len = sizeof(req),
242 .nlh.nlmsg_type = RTM_GETADDR,
243 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
244 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
245 .ifm.ifa_family = family,
246 };
247
248 return send(rth->fd, &req, sizeof(req), 0);
249 }
250
251 int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
252 {
253 struct {
254 struct nlmsghdr nlh;
255 struct ifaddrlblmsg ifal;
256 } req = {
257 .nlh.nlmsg_len = sizeof(req),
258 .nlh.nlmsg_type = RTM_GETADDRLABEL,
259 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
260 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
261 .ifal.ifal_family = family,
262 };
263
264 return send(rth->fd, &req, sizeof(req), 0);
265 }
266
267 int rtnl_routedump_req(struct rtnl_handle *rth, int family)
268 {
269 struct {
270 struct nlmsghdr nlh;
271 struct rtmsg rtm;
272 } req = {
273 .nlh.nlmsg_len = sizeof(req),
274 .nlh.nlmsg_type = RTM_GETROUTE,
275 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
276 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
277 .rtm.rtm_family = family,
278 };
279
280 return send(rth->fd, &req, sizeof(req), 0);
281 }
282
283 int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
284 {
285 struct {
286 struct nlmsghdr nlh;
287 struct fib_rule_hdr frh;
288 } req = {
289 .nlh.nlmsg_len = sizeof(req),
290 .nlh.nlmsg_type = RTM_GETRULE,
291 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
292 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
293 .frh.family = family
294 };
295
296 return send(rth->fd, &req, sizeof(req), 0);
297 }
298
299 int rtnl_neighdump_req(struct rtnl_handle *rth, int family)
300 {
301 struct {
302 struct nlmsghdr nlh;
303 struct ndmsg ndm;
304 } req = {
305 .nlh.nlmsg_len = sizeof(req),
306 .nlh.nlmsg_type = RTM_GETNEIGH,
307 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
308 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
309 .ndm.ndm_family = family,
310 };
311
312 return send(rth->fd, &req, sizeof(req), 0);
313 }
314
315 int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
316 {
317 struct {
318 struct nlmsghdr nlh;
319 struct ndtmsg ndtmsg;
320 } req = {
321 .nlh.nlmsg_len = sizeof(req),
322 .nlh.nlmsg_type = RTM_GETNEIGHTBL,
323 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
324 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
325 .ndtmsg.ndtm_family = family,
326 };
327
328 return send(rth->fd, &req, sizeof(req), 0);
329 }
330
331 int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
332 {
333 struct {
334 struct nlmsghdr nlh;
335 struct br_port_msg bpm;
336 } req = {
337 .nlh.nlmsg_len = sizeof(req),
338 .nlh.nlmsg_type = RTM_GETMDB,
339 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
340 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
341 .bpm.family = family,
342 };
343
344 return send(rth->fd, &req, sizeof(req), 0);
345 }
346
347 int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
348 {
349 struct {
350 struct nlmsghdr nlh;
351 struct netconfmsg ncm;
352 } req = {
353 .nlh.nlmsg_len = sizeof(req),
354 .nlh.nlmsg_type = RTM_GETNETCONF,
355 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
356 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
357 .ncm.ncm_family = family,
358 };
359
360 return send(rth->fd, &req, sizeof(req), 0);
361 }
362
363 int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
364 {
365 struct {
366 struct nlmsghdr nlh;
367 struct rtgenmsg rtm;
368 } req = {
369 .nlh.nlmsg_len = sizeof(req),
370 .nlh.nlmsg_type = RTM_GETNSID,
371 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
372 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
373 .rtm.rtgen_family = family,
374 };
375
376 return send(rth->fd, &req, sizeof(req), 0);
377 }
378
379 int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
380 {
381 return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
382 }
383
384 int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
385 __u32 filt_mask)
386 {
387 struct {
388 struct nlmsghdr nlh;
389 struct ifinfomsg ifm;
390 /* attribute has to be NLMSG aligned */
391 struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO)));
392 __u32 ext_filter_mask;
393 } req = {
394 .nlh.nlmsg_len = sizeof(req),
395 .nlh.nlmsg_type = RTM_GETLINK,
396 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
397 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
398 .ifm.ifi_family = family,
399 .ext_req.rta_type = IFLA_EXT_MASK,
400 .ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
401 .ext_filter_mask = filt_mask,
402 };
403
404 return send(rth->fd, &req, sizeof(req), 0);
405 }
406
407 int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
408 req_filter_fn_t filter_fn)
409 {
410 struct {
411 struct nlmsghdr nlh;
412 struct ifinfomsg ifm;
413 char buf[1024];
414 } req = {
415 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
416 .nlh.nlmsg_type = RTM_GETLINK,
417 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
418 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
419 .ifm.ifi_family = family,
420 };
421 int err;
422
423 if (!filter_fn)
424 return -EINVAL;
425
426 err = filter_fn(&req.nlh, sizeof(req));
427 if (err)
428 return err;
429
430 return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
431 }
432
433 int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
434 {
435 struct {
436 struct nlmsghdr nlh;
437 struct if_stats_msg ifsm;
438 } req;
439
440 memset(&req, 0, sizeof(req));
441 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg));
442 req.nlh.nlmsg_type = RTM_GETSTATS;
443 req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
444 req.nlh.nlmsg_pid = 0;
445 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
446 req.ifsm.family = fam;
447 req.ifsm.filter_mask = filt_mask;
448
449 return send(rth->fd, &req, sizeof(req), 0);
450 }
451
452 int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
453 {
454 return send(rth->fd, buf, len, 0);
455 }
456
457 int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
458 {
459 struct nlmsghdr *h;
460 int status;
461 char resp[1024];
462
463 status = send(rth->fd, buf, len, 0);
464 if (status < 0)
465 return status;
466
467 /* Check for immediate errors */
468 status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
469 if (status < 0) {
470 if (errno == EAGAIN)
471 return 0;
472 return -1;
473 }
474
475 for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
476 h = NLMSG_NEXT(h, status)) {
477 if (h->nlmsg_type == NLMSG_ERROR) {
478 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
479
480 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
481 fprintf(stderr, "ERROR truncated\n");
482 else
483 errno = -err->error;
484 return -1;
485 }
486 }
487
488 return 0;
489 }
490
491 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
492 {
493 struct nlmsghdr nlh = {
494 .nlmsg_len = NLMSG_LENGTH(len),
495 .nlmsg_type = type,
496 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
497 .nlmsg_seq = rth->dump = ++rth->seq,
498 };
499 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
500 struct iovec iov[2] = {
501 { .iov_base = &nlh, .iov_len = sizeof(nlh) },
502 { .iov_base = req, .iov_len = len }
503 };
504 struct msghdr msg = {
505 .msg_name = &nladdr,
506 .msg_namelen = sizeof(nladdr),
507 .msg_iov = iov,
508 .msg_iovlen = 2,
509 };
510
511 return sendmsg(rth->fd, &msg, 0);
512 }
513
514 int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
515 {
516 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
517 struct iovec iov = {
518 .iov_base = n,
519 .iov_len = n->nlmsg_len
520 };
521 struct msghdr msg = {
522 .msg_name = &nladdr,
523 .msg_namelen = sizeof(nladdr),
524 .msg_iov = &iov,
525 .msg_iovlen = 1,
526 };
527
528 n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
529 n->nlmsg_pid = 0;
530 n->nlmsg_seq = rth->dump = ++rth->seq;
531
532 return sendmsg(rth->fd, &msg, 0);
533 }
534
535 static int rtnl_dump_done(struct nlmsghdr *h)
536 {
537 int len = *(int *)NLMSG_DATA(h);
538
539 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
540 fprintf(stderr, "DONE truncated\n");
541 return -1;
542 }
543
544 if (len < 0) {
545 /* check for any messages returned from kernel */
546 if (nl_dump_ext_ack_done(h, len))
547 return len;
548
549 errno = -len;
550 switch (errno) {
551 case ENOENT:
552 case EOPNOTSUPP:
553 return -1;
554 case EMSGSIZE:
555 fprintf(stderr,
556 "Error: Buffer too small for object.\n");
557 break;
558 default:
559 perror("RTNETLINK answers");
560 }
561 return len;
562 }
563
564 /* check for any messages returned from kernel */
565 nl_dump_ext_ack(h, NULL);
566
567 return 0;
568 }
569
570 static void rtnl_dump_error(const struct rtnl_handle *rth,
571 struct nlmsghdr *h)
572 {
573
574 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
575 fprintf(stderr, "ERROR truncated\n");
576 } else {
577 const struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
578
579 errno = -err->error;
580 if (rth->proto == NETLINK_SOCK_DIAG &&
581 (errno == ENOENT ||
582 errno == EOPNOTSUPP))
583 return;
584
585 if (!(rth->flags & RTNL_HANDLE_F_SUPPRESS_NLERR))
586 perror("RTNETLINK answers");
587 }
588 }
589
590 static int __rtnl_recvmsg(int fd, struct msghdr *msg, int flags)
591 {
592 int len;
593
594 do {
595 len = recvmsg(fd, msg, flags);
596 } while (len < 0 && (errno == EINTR || errno == EAGAIN));
597
598 if (len < 0) {
599 fprintf(stderr, "netlink receive error %s (%d)\n",
600 strerror(errno), errno);
601 return -errno;
602 }
603
604 if (len == 0) {
605 fprintf(stderr, "EOF on netlink\n");
606 return -ENODATA;
607 }
608
609 return len;
610 }
611
612 static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
613 {
614 struct iovec *iov = msg->msg_iov;
615 char *buf;
616 int len;
617
618 iov->iov_base = NULL;
619 iov->iov_len = 0;
620
621 len = __rtnl_recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC);
622 if (len < 0)
623 return len;
624
625 buf = malloc(len);
626 if (!buf) {
627 fprintf(stderr, "malloc error: not enough buffer\n");
628 return -ENOMEM;
629 }
630
631 iov->iov_base = buf;
632 iov->iov_len = len;
633
634 len = __rtnl_recvmsg(fd, msg, 0);
635 if (len < 0) {
636 free(buf);
637 return len;
638 }
639
640 if (answer)
641 *answer = buf;
642 else
643 free(buf);
644
645 return len;
646 }
647
648 static int rtnl_dump_filter_l(struct rtnl_handle *rth,
649 const struct rtnl_dump_filter_arg *arg)
650 {
651 struct sockaddr_nl nladdr;
652 struct iovec iov;
653 struct msghdr msg = {
654 .msg_name = &nladdr,
655 .msg_namelen = sizeof(nladdr),
656 .msg_iov = &iov,
657 .msg_iovlen = 1,
658 };
659 char *buf;
660 int dump_intr = 0;
661
662 while (1) {
663 int status;
664 const struct rtnl_dump_filter_arg *a;
665 int found_done = 0;
666 int msglen = 0;
667
668 status = rtnl_recvmsg(rth->fd, &msg, &buf);
669 if (status < 0)
670 return status;
671
672 if (rth->dump_fp)
673 fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp);
674
675 for (a = arg; a->filter; a++) {
676 struct nlmsghdr *h = (struct nlmsghdr *)buf;
677
678 msglen = status;
679
680 while (NLMSG_OK(h, msglen)) {
681 int err = 0;
682
683 h->nlmsg_flags &= ~a->nc_flags;
684
685 if (nladdr.nl_pid != 0 ||
686 h->nlmsg_pid != rth->local.nl_pid ||
687 h->nlmsg_seq != rth->dump)
688 goto skip_it;
689
690 if (h->nlmsg_flags & NLM_F_DUMP_INTR)
691 dump_intr = 1;
692
693 if (h->nlmsg_type == NLMSG_DONE) {
694 err = rtnl_dump_done(h);
695 if (err < 0) {
696 free(buf);
697 return -1;
698 }
699
700 found_done = 1;
701 break; /* process next filter */
702 }
703
704 if (h->nlmsg_type == NLMSG_ERROR) {
705 rtnl_dump_error(rth, h);
706 free(buf);
707 return -1;
708 }
709
710 if (!rth->dump_fp) {
711 err = a->filter(h, a->arg1);
712 if (err < 0) {
713 free(buf);
714 return err;
715 }
716 }
717
718 skip_it:
719 h = NLMSG_NEXT(h, msglen);
720 }
721 }
722 free(buf);
723
724 if (found_done) {
725 if (dump_intr)
726 fprintf(stderr,
727 "Dump was interrupted and may be inconsistent.\n");
728 return 0;
729 }
730
731 if (msg.msg_flags & MSG_TRUNC) {
732 fprintf(stderr, "Message truncated\n");
733 continue;
734 }
735 if (msglen) {
736 fprintf(stderr, "!!!Remnant of size %d\n", msglen);
737 exit(1);
738 }
739 }
740 }
741
742 int rtnl_dump_filter_nc(struct rtnl_handle *rth,
743 rtnl_filter_t filter,
744 void *arg1, __u16 nc_flags)
745 {
746 const struct rtnl_dump_filter_arg a[2] = {
747 { .filter = filter, .arg1 = arg1, .nc_flags = nc_flags, },
748 { .filter = NULL, .arg1 = NULL, .nc_flags = 0, },
749 };
750
751 return rtnl_dump_filter_l(rth, a);
752 }
753
754 static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
755 nl_ext_ack_fn_t errfn)
756 {
757 if (nl_dump_ext_ack(h, errfn))
758 return;
759
760 fprintf(stderr, "RTNETLINK answers: %s\n",
761 strerror(-err->error));
762 }
763
764
765 static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iov,
766 size_t iovlen, struct nlmsghdr **answer,
767 bool show_rtnl_err, nl_ext_ack_fn_t errfn)
768 {
769 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
770 struct iovec riov;
771 struct msghdr msg = {
772 .msg_name = &nladdr,
773 .msg_namelen = sizeof(nladdr),
774 .msg_iov = iov,
775 .msg_iovlen = iovlen,
776 };
777 unsigned int seq = 0;
778 struct nlmsghdr *h;
779 int i, status;
780 char *buf;
781
782 for (i = 0; i < iovlen; i++) {
783 h = iov[i].iov_base;
784 h->nlmsg_seq = seq = ++rtnl->seq;
785 if (answer == NULL)
786 h->nlmsg_flags |= NLM_F_ACK;
787 }
788
789 status = sendmsg(rtnl->fd, &msg, 0);
790 if (status < 0) {
791 perror("Cannot talk to rtnetlink");
792 return -1;
793 }
794
795 /* change msg to use the response iov */
796 msg.msg_iov = &riov;
797 msg.msg_iovlen = 1;
798 i = 0;
799 while (1) {
800 next:
801 status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
802 ++i;
803
804 if (status < 0)
805 return status;
806
807 if (msg.msg_namelen != sizeof(nladdr)) {
808 fprintf(stderr,
809 "sender address length == %d\n",
810 msg.msg_namelen);
811 exit(1);
812 }
813 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
814 int len = h->nlmsg_len;
815 int l = len - sizeof(*h);
816
817 if (l < 0 || len > status) {
818 if (msg.msg_flags & MSG_TRUNC) {
819 fprintf(stderr, "Truncated message\n");
820 free(buf);
821 return -1;
822 }
823 fprintf(stderr,
824 "!!!malformed message: len=%d\n",
825 len);
826 exit(1);
827 }
828
829 if (nladdr.nl_pid != 0 ||
830 h->nlmsg_pid != rtnl->local.nl_pid ||
831 h->nlmsg_seq > seq || h->nlmsg_seq < seq - iovlen) {
832 /* Don't forget to skip that message. */
833 status -= NLMSG_ALIGN(len);
834 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
835 continue;
836 }
837
838 if (h->nlmsg_type == NLMSG_ERROR) {
839 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
840 int error = err->error;
841
842 if (l < sizeof(struct nlmsgerr)) {
843 fprintf(stderr, "ERROR truncated\n");
844 free(buf);
845 return -1;
846 }
847
848 if (!error) {
849 /* check messages from kernel */
850 nl_dump_ext_ack(h, errfn);
851 } else {
852 errno = -error;
853
854 if (rtnl->proto != NETLINK_SOCK_DIAG &&
855 show_rtnl_err)
856 rtnl_talk_error(h, err, errfn);
857 }
858
859 if (answer)
860 *answer = (struct nlmsghdr *)buf;
861 else
862 free(buf);
863
864 if (i < iovlen)
865 goto next;
866 return error ? -i : 0;
867 }
868
869 if (answer) {
870 *answer = (struct nlmsghdr *)buf;
871 return 0;
872 }
873
874 fprintf(stderr, "Unexpected reply!!!\n");
875
876 status -= NLMSG_ALIGN(len);
877 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
878 }
879 free(buf);
880
881 if (msg.msg_flags & MSG_TRUNC) {
882 fprintf(stderr, "Message truncated\n");
883 continue;
884 }
885
886 if (status) {
887 fprintf(stderr, "!!!Remnant of size %d\n", status);
888 exit(1);
889 }
890 }
891 }
892
893 static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
894 struct nlmsghdr **answer,
895 bool show_rtnl_err, nl_ext_ack_fn_t errfn)
896 {
897 struct iovec iov = {
898 .iov_base = n,
899 .iov_len = n->nlmsg_len
900 };
901
902 return __rtnl_talk_iov(rtnl, &iov, 1, answer, show_rtnl_err, errfn);
903 }
904
905 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
906 struct nlmsghdr **answer)
907 {
908 return __rtnl_talk(rtnl, n, answer, true, NULL);
909 }
910
911 int rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iovec, size_t iovlen,
912 struct nlmsghdr **answer)
913 {
914 return __rtnl_talk_iov(rtnl, iovec, iovlen, answer, true, NULL);
915 }
916
917 int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle *rtnl, struct nlmsghdr *n,
918 struct nlmsghdr **answer)
919 {
920 return __rtnl_talk(rtnl, n, answer, false, NULL);
921 }
922
923 int rtnl_listen_all_nsid(struct rtnl_handle *rth)
924 {
925 unsigned int on = 1;
926
927 if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
928 sizeof(on)) < 0) {
929 perror("NETLINK_LISTEN_ALL_NSID");
930 return -1;
931 }
932 rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
933 return 0;
934 }
935
936 int rtnl_listen(struct rtnl_handle *rtnl,
937 rtnl_listen_filter_t handler,
938 void *jarg)
939 {
940 int status;
941 struct nlmsghdr *h;
942 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
943 struct iovec iov;
944 struct msghdr msg = {
945 .msg_name = &nladdr,
946 .msg_namelen = sizeof(nladdr),
947 .msg_iov = &iov,
948 .msg_iovlen = 1,
949 };
950 char buf[16384];
951 char cmsgbuf[BUFSIZ];
952
953 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
954 msg.msg_control = &cmsgbuf;
955 msg.msg_controllen = sizeof(cmsgbuf);
956 }
957
958 iov.iov_base = buf;
959 while (1) {
960 struct rtnl_ctrl_data ctrl;
961 struct cmsghdr *cmsg;
962
963 iov.iov_len = sizeof(buf);
964 status = recvmsg(rtnl->fd, &msg, 0);
965
966 if (status < 0) {
967 if (errno == EINTR || errno == EAGAIN)
968 continue;
969 fprintf(stderr, "netlink receive error %s (%d)\n",
970 strerror(errno), errno);
971 if (errno == ENOBUFS)
972 continue;
973 return -1;
974 }
975 if (status == 0) {
976 fprintf(stderr, "EOF on netlink\n");
977 return -1;
978 }
979 if (msg.msg_namelen != sizeof(nladdr)) {
980 fprintf(stderr,
981 "Sender address length == %d\n",
982 msg.msg_namelen);
983 exit(1);
984 }
985
986 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
987 memset(&ctrl, 0, sizeof(ctrl));
988 ctrl.nsid = -1;
989 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
990 cmsg = CMSG_NXTHDR(&msg, cmsg))
991 if (cmsg->cmsg_level == SOL_NETLINK &&
992 cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
993 cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
994 int *data = (int *)CMSG_DATA(cmsg);
995
996 ctrl.nsid = *data;
997 }
998 }
999
1000 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
1001 int err;
1002 int len = h->nlmsg_len;
1003 int l = len - sizeof(*h);
1004
1005 if (l < 0 || len > status) {
1006 if (msg.msg_flags & MSG_TRUNC) {
1007 fprintf(stderr, "Truncated message\n");
1008 return -1;
1009 }
1010 fprintf(stderr,
1011 "!!!malformed message: len=%d\n",
1012 len);
1013 exit(1);
1014 }
1015
1016 err = handler(&ctrl, h, jarg);
1017 if (err < 0)
1018 return err;
1019
1020 status -= NLMSG_ALIGN(len);
1021 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
1022 }
1023 if (msg.msg_flags & MSG_TRUNC) {
1024 fprintf(stderr, "Message truncated\n");
1025 continue;
1026 }
1027 if (status) {
1028 fprintf(stderr, "!!!Remnant of size %d\n", status);
1029 exit(1);
1030 }
1031 }
1032 }
1033
1034 int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
1035 void *jarg)
1036 {
1037 int status;
1038 char buf[16384];
1039 struct nlmsghdr *h = (struct nlmsghdr *)buf;
1040
1041 while (1) {
1042 int err, len;
1043 int l;
1044
1045 status = fread(&buf, 1, sizeof(*h), rtnl);
1046
1047 if (status < 0) {
1048 if (errno == EINTR)
1049 continue;
1050 perror("rtnl_from_file: fread");
1051 return -1;
1052 }
1053 if (status == 0)
1054 return 0;
1055
1056 len = h->nlmsg_len;
1057 l = len - sizeof(*h);
1058
1059 if (l < 0 || len > sizeof(buf)) {
1060 fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
1061 len, ftell(rtnl));
1062 return -1;
1063 }
1064
1065 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
1066
1067 if (status < 0) {
1068 perror("rtnl_from_file: fread");
1069 return -1;
1070 }
1071 if (status < l) {
1072 fprintf(stderr, "rtnl-from_file: truncated message\n");
1073 return -1;
1074 }
1075
1076 err = handler(NULL, h, jarg);
1077 if (err < 0)
1078 return err;
1079 }
1080 }
1081
1082 int addattr(struct nlmsghdr *n, int maxlen, int type)
1083 {
1084 return addattr_l(n, maxlen, type, NULL, 0);
1085 }
1086
1087 int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
1088 {
1089 return addattr_l(n, maxlen, type, &data, sizeof(__u8));
1090 }
1091
1092 int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
1093 {
1094 return addattr_l(n, maxlen, type, &data, sizeof(__u16));
1095 }
1096
1097 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
1098 {
1099 return addattr_l(n, maxlen, type, &data, sizeof(__u32));
1100 }
1101
1102 int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
1103 {
1104 return addattr_l(n, maxlen, type, &data, sizeof(__u64));
1105 }
1106
1107 int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
1108 {
1109 return addattr_l(n, maxlen, type, str, strlen(str)+1);
1110 }
1111
1112 int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
1113 int alen)
1114 {
1115 int len = RTA_LENGTH(alen);
1116 struct rtattr *rta;
1117
1118 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
1119 fprintf(stderr,
1120 "addattr_l ERROR: message exceeded bound of %d\n",
1121 maxlen);
1122 return -1;
1123 }
1124 rta = NLMSG_TAIL(n);
1125 rta->rta_type = type;
1126 rta->rta_len = len;
1127 if (alen)
1128 memcpy(RTA_DATA(rta), data, alen);
1129 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
1130 return 0;
1131 }
1132
1133 int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
1134 {
1135 if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
1136 fprintf(stderr,
1137 "addraw_l ERROR: message exceeded bound of %d\n",
1138 maxlen);
1139 return -1;
1140 }
1141
1142 memcpy(NLMSG_TAIL(n), data, len);
1143 memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
1144 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
1145 return 0;
1146 }
1147
1148 struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
1149 {
1150 struct rtattr *nest = NLMSG_TAIL(n);
1151
1152 addattr_l(n, maxlen, type, NULL, 0);
1153 return nest;
1154 }
1155
1156 int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
1157 {
1158 nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
1159 return n->nlmsg_len;
1160 }
1161
1162 struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
1163 const void *data, int len)
1164 {
1165 struct rtattr *start = NLMSG_TAIL(n);
1166
1167 addattr_l(n, maxlen, type, data, len);
1168 addattr_nest(n, maxlen, type);
1169 return start;
1170 }
1171
1172 int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
1173 {
1174 struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
1175
1176 start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
1177 addattr_nest_end(n, nest);
1178 return n->nlmsg_len;
1179 }
1180
1181 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
1182 {
1183 int len = RTA_LENGTH(4);
1184 struct rtattr *subrta;
1185
1186 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
1187 fprintf(stderr,
1188 "rta_addattr32: Error! max allowed bound %d exceeded\n",
1189 maxlen);
1190 return -1;
1191 }
1192 subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
1193 subrta->rta_type = type;
1194 subrta->rta_len = len;
1195 memcpy(RTA_DATA(subrta), &data, 4);
1196 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
1197 return 0;
1198 }
1199
1200 int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
1201 const void *data, int alen)
1202 {
1203 struct rtattr *subrta;
1204 int len = RTA_LENGTH(alen);
1205
1206 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
1207 fprintf(stderr,
1208 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
1209 maxlen);
1210 return -1;
1211 }
1212 subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
1213 subrta->rta_type = type;
1214 subrta->rta_len = len;
1215 if (alen)
1216 memcpy(RTA_DATA(subrta), data, alen);
1217 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
1218 return 0;
1219 }
1220
1221 int rta_addattr8(struct rtattr *rta, int maxlen, int type, __u8 data)
1222 {
1223 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u8));
1224 }
1225
1226 int rta_addattr16(struct rtattr *rta, int maxlen, int type, __u16 data)
1227 {
1228 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u16));
1229 }
1230
1231 int rta_addattr64(struct rtattr *rta, int maxlen, int type, __u64 data)
1232 {
1233 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u64));
1234 }
1235
1236 struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type)
1237 {
1238 struct rtattr *nest = RTA_TAIL(rta);
1239
1240 rta_addattr_l(rta, maxlen, type, NULL, 0);
1241
1242 return nest;
1243 }
1244
1245 int rta_nest_end(struct rtattr *rta, struct rtattr *nest)
1246 {
1247 nest->rta_len = (void *)RTA_TAIL(rta) - (void *)nest;
1248
1249 return rta->rta_len;
1250 }
1251
1252 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
1253 {
1254 return parse_rtattr_flags(tb, max, rta, len, 0);
1255 }
1256
1257 int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
1258 int len, unsigned short flags)
1259 {
1260 unsigned short type;
1261
1262 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
1263 while (RTA_OK(rta, len)) {
1264 type = rta->rta_type & ~flags;
1265 if ((type <= max) && (!tb[type]))
1266 tb[type] = rta;
1267 rta = RTA_NEXT(rta, len);
1268 }
1269 if (len)
1270 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
1271 len, rta->rta_len);
1272 return 0;
1273 }
1274
1275 struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
1276 {
1277 while (RTA_OK(rta, len)) {
1278 if (rta->rta_type == type)
1279 return rta;
1280 rta = RTA_NEXT(rta, len);
1281 }
1282
1283 if (len)
1284 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
1285 len, rta->rta_len);
1286 return NULL;
1287 }
1288
1289 int __parse_rtattr_nested_compat(struct rtattr *tb[], int max,
1290 struct rtattr *rta,
1291 int len)
1292 {
1293 if (RTA_PAYLOAD(rta) < len)
1294 return -1;
1295 if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
1296 rta = RTA_DATA(rta) + RTA_ALIGN(len);
1297 return parse_rtattr_nested(tb, max, rta);
1298 }
1299 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
1300 return 0;
1301 }