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 <unistd.h> 16 #include <syslog.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 26 #include "log.h" 27 #include "libnetlink.h" 28 29 #ifndef DEFAULT_RTNL_BUFSIZE 30 #define DEFAULT_RTNL_BUFSIZE 4 * 1024 * 1024 31 #endif 32 33 #ifndef RTNL_SND_BUFSIZE 34 #define RTNL_SND_BUFSIZE DEFAULT_RTNL_BUFSIZE 35 #endif 36 #ifndef RTNL_RCV_BUFSIZE 37 #define RTNL_RCV_BUFSIZE DEFAULT_RTNL_BUFSIZE 38 #endif 39 40 void rtnl_close(struct rtnl_handle *rth) 41 { 42 close(rth->fd); 43 } 44 45 int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, 46 int protocol) 47 { 48 socklen_t addr_len; 49 int sndbuf = RTNL_SND_BUFSIZE; 50 int rcvbuf = RTNL_RCV_BUFSIZE; 51 int yes = 1; 52 53 memset(rth, 0, sizeof(*rth)); 54 55 rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol); 56 if (rth->fd < 0) { 57 ERROR("Cannot open netlink socket"); 58 return -1; 59 } 60 61 if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) 62 < 0) { 63 ERROR("SO_SNDBUF"); 64 return -1; 65 } 66 67 if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) 68 < 0) { 69 ERROR("SO_RCVBUF"); 70 return -1; 71 } 72 73 if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &yes, sizeof(yes)) < 0) 74 ERROR("NETLINK_NO_EBUFS"); 75 76 memset(&rth->local, 0, sizeof(rth->local)); 77 rth->local.nl_family = AF_NETLINK; 78 rth->local.nl_groups = subscriptions; 79 80 if (bind(rth->fd, (struct sockaddr *)&rth->local, sizeof(rth->local)) < 81 0) { 82 ERROR("Cannot bind netlink socket"); 83 return -1; 84 } 85 addr_len = sizeof(rth->local); 86 if (getsockname(rth->fd, (struct sockaddr *)&rth->local, &addr_len) < 0) { 87 ERROR("Cannot getsockname"); 88 return -1; 89 } 90 if (addr_len != sizeof(rth->local)) { 91 ERROR("Wrong address length %d\n", addr_len); 92 return -1; 93 } 94 if (rth->local.nl_family != AF_NETLINK) { 95 ERROR("Wrong address family %d\n", 96 rth->local.nl_family); 97 return -1; 98 } 99 rth->seq = time(NULL); 100 return 0; 101 } 102 103 int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) 104 { 105 return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); 106 } 107 108 int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) 109 { 110 struct { 111 struct nlmsghdr nlh; 112 struct rtgenmsg g; 113 } req; 114 struct sockaddr_nl nladdr; 115 116 memset(&nladdr, 0, sizeof(nladdr)); 117 nladdr.nl_family = AF_NETLINK; 118 119 memset(&req, 0, sizeof(req)); 120 req.nlh.nlmsg_len = sizeof(req); 121 req.nlh.nlmsg_type = type; 122 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; 123 req.nlh.nlmsg_pid = 0; 124 req.nlh.nlmsg_seq = rth->dump = ++rth->seq; 125 req.g.rtgen_family = family; 126 127 return sendto(rth->fd, (void *)&req, sizeof(req), 0, 128 (struct sockaddr *)&nladdr, sizeof(nladdr)); 129 } 130 131 int rtnl_send(struct rtnl_handle *rth, const char *buf, int len) 132 { 133 struct sockaddr_nl nladdr; 134 135 memset(&nladdr, 0, sizeof(nladdr)); 136 nladdr.nl_family = AF_NETLINK; 137 138 return sendto(rth->fd, buf, len, 0, (struct sockaddr *)&nladdr, 139 sizeof(nladdr)); 140 } 141 142 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) 143 { 144 struct nlmsghdr nlh; 145 struct sockaddr_nl nladdr; 146 struct iovec iov[2] = { 147 {.iov_base = &nlh,.iov_len = sizeof(nlh)} 148 , 149 {.iov_base = req,.iov_len = len} 150 }; 151 struct msghdr msg = { 152 .msg_name = &nladdr, 153 .msg_namelen = sizeof(nladdr), 154 .msg_iov = iov, 155 .msg_iovlen = 2, 156 }; 157 158 memset(&nladdr, 0, sizeof(nladdr)); 159 nladdr.nl_family = AF_NETLINK; 160 161 nlh.nlmsg_len = NLMSG_LENGTH(len); 162 nlh.nlmsg_type = type; 163 nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; 164 nlh.nlmsg_pid = 0; 165 nlh.nlmsg_seq = rth->dump = ++rth->seq; 166 167 return sendmsg(rth->fd, &msg, 0); 168 } 169 170 int rtnl_dump_filter(struct rtnl_handle *rth, 171 rtnl_filter_t filter, 172 void *arg1, rtnl_filter_t junk, void *arg2) 173 { 174 struct sockaddr_nl nladdr; 175 struct iovec iov; 176 struct msghdr msg = { 177 .msg_name = &nladdr, 178 .msg_namelen = sizeof(nladdr), 179 .msg_iov = &iov, 180 .msg_iovlen = 1, 181 }; 182 char buf[16384]; 183 184 iov.iov_base = buf; 185 while (1) { 186 int status; 187 struct nlmsghdr *h; 188 189 iov.iov_len = sizeof(buf); 190 status = recvmsg(rth->fd, &msg, 0); 191 192 if (status < 0) { 193 if (errno == EINTR) 194 continue; 195 ERROR("OVERRUN"); 196 continue; 197 } 198 199 if (status == 0) { 200 ERROR("EOF on netlink\n"); 201 return -1; 202 } 203 204 h = (struct nlmsghdr *)buf; 205 while (NLMSG_OK(h, status)) { 206 int err; 207 208 if (nladdr.nl_pid != 0 || 209 h->nlmsg_pid != rth->local.nl_pid || 210 h->nlmsg_seq != rth->dump) { 211 if (junk) { 212 err = junk(&nladdr, h, arg2); 213 if (err < 0) 214 return err; 215 } 216 goto skip_it; 217 } 218 219 if (h->nlmsg_type == NLMSG_DONE) 220 return 0; 221 if (h->nlmsg_type == NLMSG_ERROR) { 222 struct nlmsgerr *err = 223 (struct nlmsgerr *)NLMSG_DATA(h); 224 if (h->nlmsg_len < 225 NLMSG_LENGTH(sizeof(struct nlmsgerr))) { 226 ERROR("ERROR truncated\n"); 227 } else { 228 errno = -err->error; 229 LOG("RTNETLINK answers"); 230 } 231 return -1; 232 } 233 err = filter(&nladdr, h, arg1); 234 if (err < 0) 235 return err; 236 237 skip_it: 238 h = NLMSG_NEXT(h, status); 239 } 240 if (msg.msg_flags & MSG_TRUNC) { 241 ERROR("Message truncated\n"); 242 continue; 243 } 244 if (status) { 245 ERROR("!!!Remnant of size %d\n", status); 246 return -1; 247 } 248 } 249 } 250 251 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, 252 unsigned groups, struct nlmsghdr *answer, 253 rtnl_filter_t junk, void *jarg) 254 { 255 int status; 256 unsigned seq; 257 struct nlmsghdr *h; 258 struct sockaddr_nl nladdr; 259 struct iovec iov = { 260 .iov_base = (void *)n, 261 .iov_len = n->nlmsg_len 262 }; 263 struct msghdr msg = { 264 .msg_name = &nladdr, 265 .msg_namelen = sizeof(nladdr), 266 .msg_iov = &iov, 267 .msg_iovlen = 1, 268 }; 269 char buf[16384]; 270 271 memset(&nladdr, 0, sizeof(nladdr)); 272 nladdr.nl_family = AF_NETLINK; 273 nladdr.nl_pid = peer; 274 nladdr.nl_groups = groups; 275 276 n->nlmsg_seq = seq = ++rtnl->seq; 277 278 if (answer == NULL) 279 n->nlmsg_flags |= NLM_F_ACK; 280 281 status = sendmsg(rtnl->fd, &msg, 0); 282 283 if (status < 0) { 284 ERROR("Cannot talk to rtnetlink"); 285 return -1; 286 } 287 288 memset(buf, 0, sizeof(buf)); 289 290 iov.iov_base = buf; 291 292 while (1) { 293 iov.iov_len = sizeof(buf); 294 status = recvmsg(rtnl->fd, &msg, 0); 295 296 if (status < 0) { 297 if (errno == EINTR) 298 continue; 299 ERROR("OVERRUN"); 300 continue; 301 } 302 if (status == 0) { 303 ERROR("EOF on netlink\n"); 304 return -1; 305 } 306 if (msg.msg_namelen != sizeof(nladdr)) { 307 ERROR("sender address length == %d\n", 308 msg.msg_namelen); 309 return -1; 310 } 311 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h);) { 312 int err; 313 int len = h->nlmsg_len; 314 int l = len - sizeof(*h); 315 316 if (l < 0 || len > status) { 317 if (msg.msg_flags & MSG_TRUNC) { 318 ERROR("Truncated message\n"); 319 return -1; 320 } 321 ERROR( 322 "!!!malformed message: len=%d\n", len); 323 return -1; 324 } 325 326 if (nladdr.nl_pid != peer || 327 h->nlmsg_pid != rtnl->local.nl_pid || 328 h->nlmsg_seq != seq) { 329 if (junk) { 330 err = junk(&nladdr, h, jarg); 331 if (err < 0) 332 return err; 333 } 334 /* Don't forget to skip that message. */ 335 status -= NLMSG_ALIGN(len); 336 h = (struct nlmsghdr *)((char *)h + 337 NLMSG_ALIGN(len)); 338 continue; 339 } 340 341 if (h->nlmsg_type == NLMSG_ERROR) { 342 struct nlmsgerr *err = 343 (struct nlmsgerr *)NLMSG_DATA(h); 344 if (l < sizeof(struct nlmsgerr)) { 345 ERROR("ERROR truncated\n"); 346 } else { 347 errno = -err->error; 348 if (errno == 0) { 349 if (answer) 350 memcpy(answer, h, 351 h->nlmsg_len); 352 return 0; 353 } 354 LOG("RTNETLINK answers"); 355 } 356 return -1; 357 } 358 if (answer) { 359 memcpy(answer, h, h->nlmsg_len); 360 return 0; 361 } 362 363 ERROR("Unexpected reply!!!\n"); 364 365 status -= NLMSG_ALIGN(len); 366 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); 367 } 368 if (msg.msg_flags & MSG_TRUNC) { 369 ERROR("Message truncated\n"); 370 continue; 371 } 372 if (status) { 373 ERROR("!!!Remnant of size %d\n", status); 374 return -1; 375 } 376 } 377 } 378 379 int rtnl_listen(struct rtnl_handle *rtnl, rtnl_filter_t handler, void *jarg) 380 { 381 int status; 382 struct nlmsghdr *h; 383 struct sockaddr_nl nladdr; 384 struct iovec iov; 385 struct msghdr msg = { 386 .msg_name = &nladdr, 387 .msg_namelen = sizeof(nladdr), 388 .msg_iov = &iov, 389 .msg_iovlen = 1, 390 }; 391 char buf[8192]; 392 393 memset(&nladdr, 0, sizeof(nladdr)); 394 nladdr.nl_family = AF_NETLINK; 395 nladdr.nl_pid = 0; 396 nladdr.nl_groups = 0; 397 398 iov.iov_base = buf; 399 while (1) { 400 iov.iov_len = sizeof(buf); 401 status = recvmsg(rtnl->fd, &msg, 0); 402 403 if (status < 0) { 404 if (errno == EINTR) 405 continue; 406 if (errno == EAGAIN) 407 return 0; 408 ERROR("OVERRUN: recvmsg(): error %d : %s\n", errno, strerror(errno)); 409 return -1; 410 } 411 if (status == 0) { 412 ERROR("EOF on netlink\n"); 413 return -1; 414 } 415 if (msg.msg_namelen != sizeof(nladdr)) { 416 ERROR("Sender address length == %d\n", 417 msg.msg_namelen); 418 continue; 419 } 420 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h);) { 421 int err; 422 int len = h->nlmsg_len; 423 int l = len - sizeof(*h); 424 425 if (l < 0 || len > status) { 426 if (msg.msg_flags & MSG_TRUNC) { 427 ERROR("Truncated message\n"); 428 continue; 429 } 430 ERROR( 431 "!!!malformed message: len=%d\n", len); 432 continue; 433 } 434 435 err = handler(&nladdr, h, jarg); 436 if (err < 0) { 437 ERROR("Handler returned %d\n", err); 438 continue; 439 } 440 441 status -= NLMSG_ALIGN(len); 442 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); 443 } 444 if (msg.msg_flags & MSG_TRUNC) { 445 ERROR("Message truncated\n"); 446 continue; 447 } 448 if (status) { 449 ERROR("!!!Remnant of size %d\n", status); 450 continue; 451 } 452 } 453 } 454 455 int rtnl_from_file(FILE * rtnl, rtnl_filter_t handler, void *jarg) 456 { 457 int status; 458 struct sockaddr_nl nladdr; 459 char buf[8192]; 460 struct nlmsghdr *h = (void *)buf; 461 462 memset(&nladdr, 0, sizeof(nladdr)); 463 nladdr.nl_family = AF_NETLINK; 464 nladdr.nl_pid = 0; 465 nladdr.nl_groups = 0; 466 467 while (1) { 468 int err, len; 469 int l; 470 471 status = fread(&buf, 1, sizeof(*h), rtnl); 472 473 if (status < 0) { 474 if (errno == EINTR) 475 continue; 476 ERROR("rtnl_from_file: fread"); 477 return -1; 478 } 479 if (status == 0) 480 return 0; 481 482 len = h->nlmsg_len; 483 l = len - sizeof(*h); 484 485 if (l < 0 || len > sizeof(buf)) { 486 ERROR("!!!malformed message: len=%d @%lu\n", 487 len, ftell(rtnl)); 488 return -1; 489 } 490 491 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); 492 493 if (status < 0) { 494 ERROR("rtnl_from_file: fread"); 495 return -1; 496 } 497 if (status < l) { 498 ERROR("rtnl-from_file: truncated message\n"); 499 return -1; 500 } 501 502 err = handler(&nladdr, h, jarg); 503 if (err < 0) 504 return err; 505 } 506 } 507 508 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) 509 { 510 int len = RTA_LENGTH(4); 511 struct rtattr *rta; 512 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) { 513 ERROR( 514 "addattr32: Error! max allowed bound %d exceeded\n", 515 maxlen); 516 return -1; 517 } 518 rta = NLMSG_TAIL(n); 519 rta->rta_type = type; 520 rta->rta_len = len; 521 memcpy(RTA_DATA(rta), &data, 4); 522 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; 523 return 0; 524 } 525 526 int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data) 527 { 528 int len = RTA_LENGTH(1); 529 struct rtattr *rta; 530 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) { 531 ERROR( 532 "addattr8: Error! max allowed bound %d exceeded\n", 533 maxlen); 534 return -1; 535 } 536 rta = NLMSG_TAIL(n); 537 rta->rta_type = type; 538 rta->rta_len = len; 539 memcpy(RTA_DATA(rta), &data, 1); 540 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; 541 return 0; 542 } 543 544 int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, 545 int alen) 546 { 547 int len = RTA_LENGTH(alen); 548 struct rtattr *rta; 549 550 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { 551 ERROR( 552 "addattr_l ERROR: message exceeded bound of %d\n", 553 maxlen); 554 return -1; 555 } 556 rta = NLMSG_TAIL(n); 557 rta->rta_type = type; 558 rta->rta_len = len; 559 memcpy(RTA_DATA(rta), data, alen); 560 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); 561 return 0; 562 } 563 564 int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) 565 { 566 if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { 567 ERROR( 568 "addraw_l ERROR: message exceeded bound of %d\n", 569 maxlen); 570 return -1; 571 } 572 573 memcpy(NLMSG_TAIL(n), data, len); 574 memset((void *)NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); 575 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); 576 return 0; 577 } 578 579 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) 580 { 581 int len = RTA_LENGTH(4); 582 struct rtattr *subrta; 583 584 if (RTA_ALIGN(rta->rta_len) + len > maxlen) { 585 ERROR( 586 "rta_addattr32: Error! max allowed bound %d exceeded\n", 587 maxlen); 588 return -1; 589 } 590 subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); 591 subrta->rta_type = type; 592 subrta->rta_len = len; 593 memcpy(RTA_DATA(subrta), &data, 4); 594 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; 595 return 0; 596 } 597 598 int rta_addattr_l(struct rtattr *rta, int maxlen, int type, 599 const void *data, int alen) 600 { 601 struct rtattr *subrta; 602 int len = RTA_LENGTH(alen); 603 604 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { 605 ERROR( 606 "rta_addattr_l: Error! max allowed bound %d exceeded\n", 607 maxlen); 608 return -1; 609 } 610 subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); 611 subrta->rta_type = type; 612 subrta->rta_len = len; 613 memcpy(RTA_DATA(subrta), data, alen); 614 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); 615 return 0; 616 } 617 618 int rta_addattr8(struct rtattr *rta, int maxlen, int type, __u8 data) 619 { 620 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u8)); 621 } 622 623 int rta_addattr16(struct rtattr *rta, int maxlen, int type, __u16 data) 624 { 625 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u16)); 626 } 627 628 int rta_addattr64(struct rtattr *rta, int maxlen, int type, __u64 data) 629 { 630 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u64)); 631 } 632 633 struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type) 634 { 635 struct rtattr *nest = RTA_TAIL(rta); 636 637 rta_addattr_l(rta, maxlen, type, NULL, 0); 638 nest->rta_type |= NLA_F_NESTED; 639 640 return nest; 641 } 642 643 int rta_nest_end(struct rtattr *rta, struct rtattr *nest) 644 { 645 nest->rta_len = (void *)RTA_TAIL(rta) - (void *)nest; 646 647 return rta->rta_len; 648 } 649 650 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 651 { 652 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); 653 while (RTA_OK(rta, len)) { 654 if (rta->rta_type <= max) 655 tb[rta->rta_type] = rta; 656 rta = RTA_NEXT(rta, len); 657 } 658 if (len) 659 ERROR("!!!Deficit %d, rta_len=%d\n", len, 660 rta->rta_len); 661 return 0; 662 } 663 664 int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, 665 int len) 666 { 667 int i = 0; 668 669 memset(tb, 0, sizeof(struct rtattr *) * max); 670 while (RTA_OK(rta, len)) { 671 if (rta->rta_type <= max && i < max) 672 tb[i++] = rta; 673 rta = RTA_NEXT(rta, len); 674 } 675 if (len) 676 ERROR("!!!Deficit %d, rta_len=%d\n", len, 677 rta->rta_len); 678 return i; 679 } 680
This page was automatically generated by LXR 0.3.1. • OpenWrt