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