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