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