1 /** 2 * Copyright (C) 2017 Hans Dedecker <dedeckeh@gmail.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License v2 as published by 6 * the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 */ 14 15 #include <errno.h> 16 #include <string.h> 17 18 #include <linux/netlink.h> 19 #include <linux/if_addr.h> 20 #include <linux/neighbour.h> 21 #include <linux/rtnetlink.h> 22 23 #include <netlink/msg.h> 24 #include <netlink/socket.h> 25 #include <netlink/attr.h> 26 27 #include <arpa/inet.h> 28 #include <libubox/list.h> 29 30 #include "odhcpd.h" 31 32 struct event_socket { 33 struct odhcpd_event ev; 34 struct nl_sock *sock; 35 int sock_bufsize; 36 }; 37 38 static void handle_rtnl_event(struct odhcpd_event *ev); 39 static int cb_rtnl_valid(struct nl_msg *msg, void *arg); 40 static void catch_rtnl_err(struct odhcpd_event *e, int error); 41 static struct nl_sock *create_socket(int protocol); 42 43 static struct nl_sock *rtnl_socket = NULL; 44 struct list_head netevent_handler_list = LIST_HEAD_INIT(netevent_handler_list); 45 static struct event_socket rtnl_event = { 46 .ev = { 47 .uloop = {.fd = - 1, }, 48 .handle_dgram = NULL, 49 .handle_error = catch_rtnl_err, 50 .recv_msgs = handle_rtnl_event, 51 }, 52 .sock = NULL, 53 .sock_bufsize = 133120, 54 }; 55 56 int netlink_init(void) 57 { 58 rtnl_socket = create_socket(NETLINK_ROUTE); 59 if (!rtnl_socket) { 60 error("Unable to open nl socket: %m"); 61 goto err; 62 } 63 64 rtnl_event.sock = create_socket(NETLINK_ROUTE); 65 if (!rtnl_event.sock) { 66 error("Unable to open nl event socket: %m"); 67 goto err; 68 } 69 70 rtnl_event.ev.uloop.fd = nl_socket_get_fd(rtnl_event.sock); 71 72 if (nl_socket_set_buffer_size(rtnl_event.sock, rtnl_event.sock_bufsize, 0)) 73 goto err; 74 75 nl_socket_disable_seq_check(rtnl_event.sock); 76 77 nl_socket_modify_cb(rtnl_event.sock, NL_CB_VALID, NL_CB_CUSTOM, 78 cb_rtnl_valid, NULL); 79 80 /* Receive IPv4 address, IPv6 address, IPv6 routes and neighbor events */ 81 if (nl_socket_add_memberships(rtnl_event.sock, RTNLGRP_IPV4_IFADDR, 82 RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE, 83 RTNLGRP_NEIGH, RTNLGRP_LINK, 0)) 84 goto err; 85 86 odhcpd_register(&rtnl_event.ev); 87 88 return 0; 89 90 err: 91 if (rtnl_socket) { 92 nl_socket_free(rtnl_socket); 93 rtnl_socket = NULL; 94 } 95 96 if (rtnl_event.sock) { 97 nl_socket_free(rtnl_event.sock); 98 rtnl_event.sock = NULL; 99 rtnl_event.ev.uloop.fd = -1; 100 } 101 102 return -1; 103 } 104 105 106 int netlink_add_netevent_handler(struct netevent_handler *handler) 107 { 108 if (!handler->cb) 109 return -1; 110 111 list_add(&handler->head, &netevent_handler_list); 112 113 return 0; 114 } 115 116 static void call_netevent_handler_list(unsigned long event, struct netevent_handler_info *info) 117 { 118 struct netevent_handler *handler; 119 120 list_for_each_entry(handler, &netevent_handler_list, head) 121 handler->cb(event, info); 122 } 123 124 static void handle_rtnl_event(struct odhcpd_event *e) 125 { 126 struct event_socket *ev_sock = container_of(e, struct event_socket, ev); 127 128 nl_recvmsgs_default(ev_sock->sock); 129 } 130 131 static void refresh_iface_addr4(int ifindex) 132 { 133 struct odhcpd_ipaddr *oaddrs4 = NULL; 134 struct interface *iface; 135 ssize_t oaddrs4_cnt = netlink_get_interface_addrs(ifindex, false, &oaddrs4); 136 bool change = false; 137 138 if (oaddrs4_cnt < 0) 139 return; 140 141 avl_for_each_element(&interfaces, iface, avl) { 142 struct netevent_handler_info event_info; 143 144 if (iface->ifindex != ifindex) 145 continue; 146 147 memset(&event_info, 0, sizeof(event_info)); 148 event_info.iface = iface; 149 event_info.addrs_old.addrs = iface->oaddrs4; 150 event_info.addrs_old.len = iface->oaddrs4_cnt; 151 152 if (!change) { 153 change = oaddrs4_cnt != (ssize_t)iface->oaddrs4_cnt; 154 for (ssize_t i = 0; !change && i < oaddrs4_cnt; i++) { 155 if (oaddrs4[i].addr.in.s_addr != iface->oaddrs4[i].addr.in.s_addr) 156 change = true; 157 } 158 } 159 160 iface->oaddrs4 = oaddrs4; 161 iface->oaddrs4_cnt = oaddrs4_cnt; 162 163 if (change) 164 call_netevent_handler_list(NETEV_ADDRLIST_CHANGE, &event_info); 165 166 free(event_info.addrs_old.addrs); 167 168 if (!oaddrs4_cnt) 169 continue; 170 171 oaddrs4 = malloc(oaddrs4_cnt * sizeof(*oaddrs4)); 172 if (!oaddrs4) 173 break; 174 175 memcpy(oaddrs4, iface->oaddrs4, oaddrs4_cnt * sizeof(*oaddrs4)); 176 } 177 178 free(oaddrs4); 179 } 180 181 static void refresh_iface_addr6(int ifindex) 182 { 183 struct odhcpd_ipaddr *oaddrs6 = NULL; 184 struct interface *iface; 185 ssize_t oaddrs6_cnt = netlink_get_interface_addrs(ifindex, true, &oaddrs6); 186 time_t now = odhcpd_time(); 187 bool change = false; 188 189 if (oaddrs6_cnt < 0) 190 return; 191 192 avl_for_each_element(&interfaces, iface, avl) { 193 struct netevent_handler_info event_info; 194 195 if (iface->ifindex != ifindex) 196 continue; 197 198 memset(&event_info, 0, sizeof(event_info)); 199 event_info.iface = iface; 200 event_info.addrs_old.addrs = iface->addr6; 201 event_info.addrs_old.len = iface->addr6_len; 202 203 if (!change) { 204 change = oaddrs6_cnt != (ssize_t)iface->addr6_len; 205 for (ssize_t i = 0; !change && i < oaddrs6_cnt; ++i) { 206 if (!IN6_ARE_ADDR_EQUAL(&oaddrs6[i].addr.in6, &iface->addr6[i].addr.in6) || 207 oaddrs6[i].prefix_len != iface->addr6[i].prefix_len || 208 (oaddrs6[i].preferred_lt > (uint32_t)now) != (iface->addr6[i].preferred_lt > (uint32_t)now) || 209 oaddrs6[i].valid_lt < iface->addr6[i].valid_lt || oaddrs6[i].preferred_lt < iface->addr6[i].preferred_lt) 210 change = true; 211 } 212 } 213 214 iface->addr6 = oaddrs6; 215 iface->addr6_len = oaddrs6_cnt; 216 217 if (change) 218 call_netevent_handler_list(NETEV_ADDR6LIST_CHANGE, &event_info); 219 220 free(event_info.addrs_old.addrs); 221 222 if (!oaddrs6_cnt) 223 continue; 224 225 oaddrs6 = malloc(oaddrs6_cnt * sizeof(*oaddrs6)); 226 if (!oaddrs6) 227 break; 228 229 memcpy(oaddrs6, iface->addr6, oaddrs6_cnt * sizeof(*oaddrs6)); 230 } 231 232 free(oaddrs6); 233 } 234 235 static int handle_rtm_link(struct nlmsghdr *hdr) 236 { 237 struct ifinfomsg *ifi = nlmsg_data(hdr); 238 struct nlattr *nla[__IFLA_MAX]; 239 struct interface *iface; 240 struct netevent_handler_info event_info; 241 const char *ifname; 242 243 memset(&event_info, 0, sizeof(event_info)); 244 245 if (!nlmsg_valid_hdr(hdr, sizeof(*ifi)) || ifi->ifi_family != AF_UNSPEC) 246 return NL_SKIP; 247 248 nlmsg_parse(hdr, sizeof(*ifi), nla, __IFLA_MAX - 1, NULL); 249 if (!nla[IFLA_IFNAME]) 250 return NL_SKIP; 251 252 ifname = nla_get_string(nla[IFLA_IFNAME]); 253 254 avl_for_each_element(&interfaces, iface, avl) { 255 if (strcmp(iface->ifname, ifname)) 256 continue; 257 258 iface->ifflags = ifi->ifi_flags; 259 260 /* store current MTU if available */ 261 if (nla[IFLA_MTU]) { 262 iface->if_mtu = nla_get_u32(nla[IFLA_MTU]); 263 debug("Netlink setting interface '%s' if_mtu MTU to %d", 264 iface->name, iface->if_mtu); 265 } 266 267 /* 268 * Assume for link event of the same index, that link changed 269 * and reload services to enable or disable them based on the 270 * RUNNING state of the interface. 271 */ 272 if (iface->ifindex == ifi->ifi_index) { 273 reload_services(iface); 274 continue; 275 } 276 277 iface->ifindex = ifi->ifi_index; 278 event_info.iface = iface; 279 call_netevent_handler_list(NETEV_IFINDEX_CHANGE, &event_info); 280 } 281 282 return NL_OK; 283 } 284 285 static int handle_rtm_route(struct nlmsghdr *hdr, bool add) 286 { 287 struct rtmsg *rtm = nlmsg_data(hdr); 288 struct nlattr *nla[__RTA_MAX]; 289 struct interface *iface; 290 struct netevent_handler_info event_info; 291 int ifindex = 0; 292 293 if (!nlmsg_valid_hdr(hdr, sizeof(*rtm)) || rtm->rtm_family != AF_INET6) 294 return NL_SKIP; 295 296 nlmsg_parse(hdr, sizeof(*rtm), nla, __RTA_MAX - 1, NULL); 297 298 memset(&event_info, 0, sizeof(event_info)); 299 event_info.rt.dst_len = rtm->rtm_dst_len; 300 301 if (nla[RTA_DST]) 302 nla_memcpy(&event_info.rt.dst, nla[RTA_DST], 303 sizeof(event_info.rt.dst)); 304 305 if (nla[RTA_OIF]) 306 ifindex = nla_get_u32(nla[RTA_OIF]); 307 308 if (nla[RTA_GATEWAY]) 309 nla_memcpy(&event_info.rt.gateway, nla[RTA_GATEWAY], 310 sizeof(event_info.rt.gateway)); 311 312 avl_for_each_element(&interfaces, iface, avl) { 313 if (ifindex && iface->ifindex != ifindex) 314 continue; 315 316 event_info.iface = ifindex ? iface : NULL; 317 call_netevent_handler_list(add ? NETEV_ROUTE6_ADD : NETEV_ROUTE6_DEL, 318 &event_info); 319 } 320 321 return NL_OK; 322 } 323 324 static int handle_rtm_addr(struct nlmsghdr *hdr, bool add) 325 { 326 struct ifaddrmsg *ifa = nlmsg_data(hdr); 327 struct nlattr *nla[__IFA_MAX]; 328 struct interface *iface; 329 struct netevent_handler_info event_info; 330 char buf[INET6_ADDRSTRLEN]; 331 332 if (!nlmsg_valid_hdr(hdr, sizeof(*ifa)) || 333 (ifa->ifa_family != AF_INET6 && 334 ifa->ifa_family != AF_INET)) 335 return NL_SKIP; 336 337 memset(&event_info, 0, sizeof(event_info)); 338 339 nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL); 340 341 if (ifa->ifa_family == AF_INET6) { 342 if (!nla[IFA_ADDRESS]) 343 return NL_SKIP; 344 345 nla_memcpy(&event_info.addr, nla[IFA_ADDRESS], sizeof(event_info.addr)); 346 347 if (IN6_IS_ADDR_MULTICAST(&event_info.addr)) 348 return NL_SKIP; 349 350 inet_ntop(AF_INET6, &event_info.addr, buf, sizeof(buf)); 351 352 avl_for_each_element(&interfaces, iface, avl) { 353 if (iface->ifindex != (int)ifa->ifa_index) 354 continue; 355 356 if (add && IN6_IS_ADDR_LINKLOCAL(&event_info.addr)) { 357 iface->have_link_local = true; 358 return NL_SKIP; 359 } 360 361 debug("Netlink %s %s on %s", add ? "newaddr" : "deladdr", 362 buf, iface->name); 363 364 event_info.iface = iface; 365 call_netevent_handler_list(add ? NETEV_ADDR6_ADD : NETEV_ADDR6_DEL, 366 &event_info); 367 } 368 369 refresh_iface_addr6(ifa->ifa_index); 370 } else { 371 if (!nla[IFA_LOCAL]) 372 return NL_SKIP; 373 374 nla_memcpy(&event_info.addr, nla[IFA_LOCAL], sizeof(event_info.addr)); 375 376 inet_ntop(AF_INET, &event_info.addr, buf, sizeof(buf)); 377 378 avl_for_each_element(&interfaces, iface, avl) { 379 if (iface->ifindex != (int)ifa->ifa_index) 380 continue; 381 382 debug("Netlink %s %s on %s", add ? "newaddr" : "deladdr", 383 buf, iface->name); 384 385 event_info.iface = iface; 386 call_netevent_handler_list(add ? NETEV_ADDR_ADD : NETEV_ADDR_DEL, 387 &event_info); 388 } 389 390 refresh_iface_addr4(ifa->ifa_index); 391 } 392 393 return NL_OK; 394 } 395 396 static int handle_rtm_neigh(struct nlmsghdr *hdr, bool add) 397 { 398 struct ndmsg *ndm = nlmsg_data(hdr); 399 struct nlattr *nla[__NDA_MAX]; 400 struct interface *iface; 401 struct netevent_handler_info event_info; 402 char buf[INET6_ADDRSTRLEN]; 403 404 if (!nlmsg_valid_hdr(hdr, sizeof(*ndm)) || 405 ndm->ndm_family != AF_INET6) 406 return NL_SKIP; 407 408 nlmsg_parse(hdr, sizeof(*ndm), nla, __NDA_MAX - 1, NULL); 409 if (!nla[NDA_DST]) 410 return NL_SKIP; 411 412 memset(&event_info, 0, sizeof(event_info)); 413 414 nla_memcpy(&event_info.neigh.dst, nla[NDA_DST], sizeof(event_info.neigh.dst)); 415 416 if (IN6_IS_ADDR_LINKLOCAL(&event_info.neigh.dst) || 417 IN6_IS_ADDR_MULTICAST(&event_info.neigh.dst)) 418 return NL_SKIP; 419 420 inet_ntop(AF_INET6, &event_info.neigh.dst, buf, sizeof(buf)); 421 422 avl_for_each_element(&interfaces, iface, avl) { 423 if (iface->ifindex != ndm->ndm_ifindex) 424 continue; 425 426 debug("Netlink %s %s on %s", add ? "newneigh" : "delneigh", 427 buf, iface->name); 428 429 event_info.iface = iface; 430 event_info.neigh.state = ndm->ndm_state; 431 event_info.neigh.flags = ndm->ndm_flags; 432 433 call_netevent_handler_list(add ? NETEV_NEIGH6_ADD : NETEV_NEIGH6_DEL, 434 &event_info); 435 } 436 437 return NL_OK; 438 } 439 440 /* Handler for neighbor cache entries from the kernel. This is our source 441 * to learn and unlearn hosts on interfaces. */ 442 static int cb_rtnl_valid(struct nl_msg *msg, _o_unused void *arg) 443 { 444 struct nlmsghdr *hdr = nlmsg_hdr(msg); 445 int ret = NL_SKIP; 446 bool add = false; 447 448 switch (hdr->nlmsg_type) { 449 case RTM_NEWLINK: 450 ret = handle_rtm_link(hdr); 451 break; 452 453 case RTM_NEWROUTE: 454 add = true; 455 _o_fallthrough; 456 case RTM_DELROUTE: 457 ret = handle_rtm_route(hdr, add); 458 break; 459 460 case RTM_NEWADDR: 461 add = true; 462 _o_fallthrough; 463 case RTM_DELADDR: 464 ret = handle_rtm_addr(hdr, add); 465 break; 466 467 case RTM_NEWNEIGH: 468 add = true; 469 _o_fallthrough; 470 case RTM_DELNEIGH: 471 ret = handle_rtm_neigh(hdr, add); 472 break; 473 474 default: 475 break; 476 } 477 478 return ret; 479 } 480 481 static void catch_rtnl_err(struct odhcpd_event *e, int error) 482 { 483 struct event_socket *ev_sock = container_of(e, struct event_socket, ev); 484 485 if (error != ENOBUFS) 486 goto err; 487 488 /* Double netlink event buffer size */ 489 ev_sock->sock_bufsize *= 2; 490 491 if (nl_socket_set_buffer_size(ev_sock->sock, ev_sock->sock_bufsize, 0)) 492 goto err; 493 494 netlink_dump_addr_table(true); 495 return; 496 497 err: 498 odhcpd_deregister(e); 499 } 500 501 static struct nl_sock *create_socket(int protocol) 502 { 503 struct nl_sock *nl_sock; 504 505 nl_sock = nl_socket_alloc(); 506 if (!nl_sock) 507 goto err; 508 509 if (nl_connect(nl_sock, protocol) < 0) 510 goto err; 511 512 return nl_sock; 513 514 err: 515 if (nl_sock) 516 nl_socket_free(nl_sock); 517 518 return NULL; 519 } 520 521 522 struct addr_info { 523 int ifindex; 524 int af; 525 struct odhcpd_ipaddr **oaddrs; 526 bool pending; 527 ssize_t ret; 528 }; 529 530 531 static int cb_addr_valid(struct nl_msg *msg, void *arg) 532 { 533 struct addr_info *ctxt = (struct addr_info *)arg; 534 struct odhcpd_ipaddr *oaddrs; 535 struct nlmsghdr *hdr = nlmsg_hdr(msg); 536 struct ifaddrmsg *ifa; 537 struct nlattr *nla[__IFA_MAX], *nla_addr = NULL; 538 539 if (hdr->nlmsg_type != RTM_NEWADDR) 540 return NL_SKIP; 541 542 ifa = NLMSG_DATA(hdr); 543 if (ifa->ifa_scope != RT_SCOPE_UNIVERSE || 544 (ctxt->af != ifa->ifa_family) || 545 (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex)) 546 return NL_SKIP; 547 548 nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL); 549 550 switch (ifa->ifa_family) { 551 case AF_INET6: 552 if (nla[IFA_ADDRESS]) 553 nla_addr = nla[IFA_ADDRESS]; 554 break; 555 556 case AF_INET: 557 if (nla[IFA_LOCAL]) 558 nla_addr = nla[IFA_LOCAL]; 559 break; 560 561 default: 562 break; 563 } 564 if (!nla_addr) 565 return NL_SKIP; 566 567 oaddrs = realloc(*(ctxt->oaddrs), sizeof(*oaddrs) * (ctxt->ret + 1)); 568 if (!oaddrs) 569 return NL_SKIP; 570 571 memset(&oaddrs[ctxt->ret], 0, sizeof(oaddrs[ctxt->ret])); 572 oaddrs[ctxt->ret].prefix_len = ifa->ifa_prefixlen; 573 574 if (ifa->ifa_family == AF_INET) 575 oaddrs[ctxt->ret].netmask = htonl(~((1U << (32 - ifa->ifa_prefixlen)) - 1)); 576 577 nla_memcpy(&oaddrs[ctxt->ret].addr, nla_addr, sizeof(oaddrs[ctxt->ret].addr)); 578 579 if (nla[IFA_BROADCAST]) 580 nla_memcpy(&oaddrs[ctxt->ret].broadcast, nla[IFA_BROADCAST], 581 sizeof(oaddrs[ctxt->ret].broadcast)); 582 583 if (nla[IFA_CACHEINFO]) { 584 struct ifa_cacheinfo *ifc = nla_data(nla[IFA_CACHEINFO]); 585 586 oaddrs[ctxt->ret].preferred_lt = ifc->ifa_prefered; 587 oaddrs[ctxt->ret].valid_lt = ifc->ifa_valid; 588 } 589 590 if (ifa->ifa_flags & IFA_F_DEPRECATED) 591 oaddrs[ctxt->ret].preferred_lt = 0; 592 593 if (ifa->ifa_family == AF_INET6 && 594 ifa->ifa_flags & IFA_F_TENTATIVE) 595 oaddrs[ctxt->ret].tentative = true; 596 597 ctxt->ret++; 598 *(ctxt->oaddrs) = oaddrs; 599 600 return NL_OK; 601 } 602 603 604 static int cb_addr_finish(_o_unused struct nl_msg *msg, void *arg) 605 { 606 struct addr_info *ctxt = (struct addr_info *)arg; 607 608 ctxt->pending = false; 609 610 return NL_STOP; 611 } 612 613 614 static int cb_addr_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err, 615 void *arg) 616 { 617 struct addr_info *ctxt = (struct addr_info *)arg; 618 619 ctxt->pending = false; 620 ctxt->ret = err->error; 621 622 return NL_STOP; 623 } 624 625 626 static int prefix_cmp(const void *va, const void *vb) 627 { 628 const struct odhcpd_ipaddr *a = va, *b = vb; 629 630 if (a->prefix_len != b->prefix_len) 631 return a->prefix_len < b->prefix_len ? 1 : -1; 632 633 if (ntohl(a->addr.in.s_addr) == ntohl(b->addr.in.s_addr)) 634 return 0; 635 636 return ntohl(a->addr.in.s_addr) < ntohl(b->addr.in.s_addr) ? 1 : -1; 637 } 638 639 640 /* compare IPv6 prefixes */ 641 static int prefix6_cmp(const void *va, const void *vb) 642 { 643 const struct odhcpd_ipaddr *a = va, *b = vb; 644 uint32_t a_pref_lt = IN6_IS_ADDR_ULA(&a->addr.in6) ? 1 : a->preferred_lt; 645 uint32_t b_pref_lt = IN6_IS_ADDR_ULA(&b->addr.in6) ? 1 : b->preferred_lt; 646 return (a_pref_lt < b_pref_lt) ? 1 : (a_pref_lt > b_pref_lt) ? -1 : 0; 647 } 648 649 650 /* Detect all IPv[46]-addresses currently assigned to the given interface */ 651 ssize_t netlink_get_interface_addrs(int ifindex, bool v6, struct odhcpd_ipaddr **oaddrs) 652 { 653 struct nl_msg *msg; 654 struct ifaddrmsg ifa = { 655 .ifa_family = v6? AF_INET6: AF_INET, 656 .ifa_prefixlen = 0, 657 .ifa_flags = 0, 658 .ifa_scope = 0, 659 .ifa_index = ifindex, 660 }; 661 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); 662 struct addr_info ctxt = { 663 .ifindex = ifindex, 664 .af = v6? AF_INET6: AF_INET, 665 .oaddrs = oaddrs, 666 .ret = 0, 667 .pending = true, 668 }; 669 670 if (!cb) { 671 ctxt.ret = -1; 672 goto out; 673 } 674 675 msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP); 676 677 if (!msg) { 678 ctxt.ret = - 1; 679 goto out; 680 } 681 682 nlmsg_append(msg, &ifa, sizeof(ifa), 0); 683 684 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_addr_valid, &ctxt); 685 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_addr_finish, &ctxt); 686 nl_cb_err(cb, NL_CB_CUSTOM, cb_addr_error, &ctxt); 687 688 ctxt.ret = nl_send_auto_complete(rtnl_socket, msg); 689 if (ctxt.ret < 0) 690 goto free; 691 692 ctxt.ret = 0; 693 while (ctxt.pending) 694 nl_recvmsgs(rtnl_socket, cb); 695 696 if (ctxt.ret <= 0) 697 goto free; 698 699 time_t now = odhcpd_time(); 700 struct odhcpd_ipaddr *oaddr = *oaddrs; 701 702 qsort(oaddr, ctxt.ret, sizeof(*oaddr), v6 ? prefix6_cmp : prefix_cmp); 703 704 for (ssize_t i = 0; i < ctxt.ret; ++i) { 705 if (oaddr[i].preferred_lt < UINT32_MAX - now) 706 oaddr[i].preferred_lt += now; 707 708 if (oaddr[i].valid_lt < UINT32_MAX - now) 709 oaddr[i].valid_lt += now; 710 } 711 712 free: 713 nlmsg_free(msg); 714 out: 715 nl_cb_put(cb); 716 717 return ctxt.ret; 718 } 719 720 721 static int cb_linklocal_valid(struct nl_msg *msg, void *arg) 722 { 723 struct addr_info *ctxt = (struct addr_info *)arg; 724 struct odhcpd_ipaddr *oaddrs; 725 struct nlmsghdr *hdr = nlmsg_hdr(msg); 726 struct ifaddrmsg *ifa; 727 struct nlattr *nla[__IFA_MAX], *nla_addr = NULL; 728 struct in6_addr addr; 729 730 if (hdr->nlmsg_type != RTM_NEWADDR) 731 return NL_SKIP; 732 733 ifa = NLMSG_DATA(hdr); 734 if (ifa->ifa_scope != RT_SCOPE_LINK || 735 (ctxt->af != ifa->ifa_family) || 736 (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex)) 737 return NL_SKIP; 738 739 nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL); 740 741 switch (ifa->ifa_family) { 742 case AF_INET6: 743 if (nla[IFA_ADDRESS]) 744 nla_addr = nla[IFA_ADDRESS]; 745 break; 746 747 default: 748 break; 749 } 750 if (!nla_addr) 751 return NL_SKIP; 752 753 nla_memcpy(&addr, nla_addr, sizeof(addr)); 754 755 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) 756 return NL_SKIP; 757 758 oaddrs = realloc(*(ctxt->oaddrs), sizeof(*oaddrs) * (ctxt->ret + 1)); 759 if (!oaddrs) 760 return NL_SKIP; 761 762 memset(&oaddrs[ctxt->ret], 0, sizeof(oaddrs[ctxt->ret])); 763 memcpy(&oaddrs[ctxt->ret].addr, &addr, sizeof(oaddrs[ctxt->ret].addr)); 764 765 if (ifa->ifa_flags & IFA_F_TENTATIVE) 766 oaddrs[ctxt->ret].tentative = true; 767 768 ctxt->ret++; 769 *(ctxt->oaddrs) = oaddrs; 770 771 return NL_OK; 772 } 773 774 775 static int cb_linklocal_finish(_o_unused struct nl_msg *msg, void *arg) 776 { 777 struct addr_info *ctxt = (struct addr_info *)arg; 778 779 ctxt->pending = false; 780 781 return NL_STOP; 782 } 783 784 785 static int cb_linklocal_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err, 786 void *arg) 787 { 788 struct addr_info *ctxt = (struct addr_info *)arg; 789 790 ctxt->pending = false; 791 ctxt->ret = err->error; 792 793 return NL_STOP; 794 } 795 796 797 /* Detect link-local IPv6-addresses currently assigned to the given interface */ 798 ssize_t netlink_get_interface_linklocal(int ifindex, struct odhcpd_ipaddr **oaddrs) 799 { 800 struct nl_msg *msg; 801 struct ifaddrmsg ifa = { 802 .ifa_family = AF_INET6, 803 .ifa_prefixlen = 0, 804 .ifa_flags = 0, 805 .ifa_scope = 0, 806 .ifa_index = ifindex, 807 }; 808 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); 809 struct addr_info ctxt = { 810 .ifindex = ifindex, 811 .af = AF_INET6, 812 .oaddrs = oaddrs, 813 .ret = 0, 814 .pending = true, 815 }; 816 817 if (!cb) { 818 ctxt.ret = -1; 819 goto out; 820 } 821 822 msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP); 823 824 if (!msg) { 825 ctxt.ret = - 1; 826 goto out; 827 } 828 829 nlmsg_append(msg, &ifa, sizeof(ifa), 0); 830 831 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_linklocal_valid, &ctxt); 832 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_linklocal_finish, &ctxt); 833 nl_cb_err(cb, NL_CB_CUSTOM, cb_linklocal_error, &ctxt); 834 835 ctxt.ret = nl_send_auto_complete(rtnl_socket, msg); 836 if (ctxt.ret < 0) 837 goto free; 838 839 ctxt.ret = 0; 840 while (ctxt.pending) 841 nl_recvmsgs(rtnl_socket, cb); 842 843 if (ctxt.ret <= 0) 844 goto free; 845 846 free: 847 nlmsg_free(msg); 848 out: 849 nl_cb_put(cb); 850 851 return ctxt.ret; 852 } 853 854 855 struct neigh_info { 856 int ifindex; 857 bool pending; 858 const struct in6_addr *addr; 859 int ret; 860 }; 861 862 863 static int cb_proxy_neigh_valid(struct nl_msg *msg, void *arg) 864 { 865 struct neigh_info *ctxt = (struct neigh_info *)arg; 866 struct nlmsghdr *hdr = nlmsg_hdr(msg); 867 struct ndmsg *ndm; 868 struct nlattr *nla_dst; 869 870 if (hdr->nlmsg_type != RTM_NEWNEIGH) 871 return NL_SKIP; 872 873 ndm = NLMSG_DATA(hdr); 874 if (ndm->ndm_family != AF_INET6 || 875 (ctxt->ifindex && ndm->ndm_ifindex != ctxt->ifindex)) 876 return NL_SKIP; 877 878 if (!(ndm->ndm_flags & NTF_PROXY)) 879 return NL_SKIP; 880 881 nla_dst = nlmsg_find_attr(hdr, sizeof(*ndm), NDA_DST); 882 if (!nla_dst) 883 return NL_SKIP; 884 885 if (nla_memcmp(nla_dst,ctxt->addr, 16) == 0) 886 ctxt->ret = 1; 887 888 return NL_OK; 889 } 890 891 892 static int cb_proxy_neigh_finish(_o_unused struct nl_msg *msg, void *arg) 893 { 894 struct neigh_info *ctxt = (struct neigh_info *)arg; 895 896 ctxt->pending = false; 897 898 return NL_STOP; 899 } 900 901 902 static int cb_proxy_neigh_error(_o_unused struct sockaddr_nl *nla, struct nlmsgerr *err, 903 void *arg) 904 { 905 struct neigh_info *ctxt = (struct neigh_info *)arg; 906 907 ctxt->pending = false; 908 ctxt->ret = err->error; 909 910 return NL_STOP; 911 } 912 913 /* Detect an IPV6-address proxy neighbor for the given interface */ 914 int netlink_get_interface_proxy_neigh(int ifindex, const struct in6_addr *addr) 915 { 916 struct nl_msg *msg; 917 struct ndmsg ndm = { 918 .ndm_family = AF_INET6, 919 .ndm_flags = NTF_PROXY, 920 .ndm_ifindex = ifindex, 921 }; 922 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); 923 struct neigh_info ctxt = { 924 .ifindex = ifindex, 925 .addr = addr, 926 .ret = 0, 927 .pending = true, 928 }; 929 930 if (!cb) { 931 ctxt.ret = -1; 932 goto out; 933 } 934 935 msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_MATCH); 936 937 if (!msg) { 938 ctxt.ret = -1; 939 goto out; 940 } 941 942 nlmsg_append(msg, &ndm, sizeof(ndm), 0); 943 nla_put(msg, NDA_DST, sizeof(*addr), addr); 944 945 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_proxy_neigh_valid, &ctxt); 946 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_proxy_neigh_finish, &ctxt); 947 nl_cb_err(cb, NL_CB_CUSTOM, cb_proxy_neigh_error, &ctxt); 948 949 ctxt.ret = nl_send_auto_complete(rtnl_socket, msg); 950 if (ctxt.ret < 0) 951 goto free; 952 953 while (ctxt.pending) 954 nl_recvmsgs(rtnl_socket, cb); 955 956 free: 957 nlmsg_free(msg); 958 out: 959 nl_cb_put(cb); 960 961 return ctxt.ret; 962 } 963 964 965 int netlink_setup_route(const struct in6_addr *addr, const int prefixlen, 966 const int ifindex, const struct in6_addr *gw, 967 const uint32_t metric, const bool add) 968 { 969 struct nl_msg *msg; 970 struct rtmsg rtm = { 971 .rtm_family = AF_INET6, 972 .rtm_dst_len = prefixlen, 973 .rtm_src_len = 0, 974 .rtm_table = RT_TABLE_MAIN, 975 .rtm_protocol = (add ? RTPROT_STATIC : RTPROT_UNSPEC), 976 .rtm_scope = (add ? (gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK) : RT_SCOPE_NOWHERE), 977 .rtm_type = (add ? RTN_UNICAST : RTN_UNSPEC), 978 }; 979 int ret = 0; 980 981 msg = nlmsg_alloc_simple(add ? RTM_NEWROUTE : RTM_DELROUTE, 982 add ? NLM_F_CREATE | NLM_F_REPLACE : 0); 983 if (!msg) 984 return -1; 985 986 nlmsg_append(msg, &rtm, sizeof(rtm), 0); 987 988 nla_put(msg, RTA_DST, sizeof(*addr), addr); 989 nla_put_u32(msg, RTA_OIF, ifindex); 990 nla_put_u32(msg, RTA_PRIORITY, metric); 991 992 if (gw) 993 nla_put(msg, RTA_GATEWAY, sizeof(*gw), gw); 994 995 ret = nl_send_auto_complete(rtnl_socket, msg); 996 nlmsg_free(msg); 997 998 if (ret < 0) 999 return ret; 1000 1001 return nl_wait_for_ack(rtnl_socket); 1002 } 1003 1004 1005 int netlink_setup_proxy_neigh(const struct in6_addr *addr, 1006 const int ifindex, const bool add) 1007 { 1008 struct nl_msg *msg; 1009 struct ndmsg ndm = { 1010 .ndm_family = AF_INET6, 1011 .ndm_flags = NTF_PROXY, 1012 .ndm_ifindex = ifindex, 1013 }; 1014 int ret = 0, flags = NLM_F_REQUEST; 1015 1016 if (add) 1017 flags |= NLM_F_REPLACE | NLM_F_CREATE; 1018 1019 msg = nlmsg_alloc_simple(add ? RTM_NEWNEIGH : RTM_DELNEIGH, flags); 1020 if (!msg) 1021 return -1; 1022 1023 nlmsg_append(msg, &ndm, sizeof(ndm), 0); 1024 1025 nla_put(msg, NDA_DST, sizeof(*addr), addr); 1026 1027 ret = nl_send_auto_complete(rtnl_socket, msg); 1028 nlmsg_free(msg); 1029 1030 if (ret < 0) 1031 return ret; 1032 1033 return nl_wait_for_ack(rtnl_socket); 1034 } 1035 1036 1037 int netlink_setup_addr(struct odhcpd_ipaddr *oaddr, 1038 const int ifindex, const bool v6, const bool add) 1039 { 1040 struct nl_msg *msg; 1041 struct ifaddrmsg ifa = { 1042 .ifa_family = v6 ? AF_INET6 : AF_INET, 1043 .ifa_prefixlen = oaddr->prefix_len, 1044 .ifa_flags = 0, 1045 .ifa_scope = 0, 1046 .ifa_index = ifindex, 1047 }; 1048 int ret = 0, flags = NLM_F_REQUEST; 1049 1050 if (add) 1051 flags |= NLM_F_REPLACE | NLM_F_CREATE; 1052 1053 msg = nlmsg_alloc_simple(add ? RTM_NEWADDR : RTM_DELADDR, 0); 1054 if (!msg) 1055 return -1; 1056 1057 nlmsg_append(msg, &ifa, sizeof(ifa), flags); 1058 nla_put(msg, IFA_LOCAL, v6 ? 16 : 4, &oaddr->addr); 1059 if (v6) { 1060 struct ifa_cacheinfo cinfo = { 1061 .ifa_prefered = 0xffffffffU, 1062 .ifa_valid = 0xffffffffU, 1063 .cstamp = 0, 1064 .tstamp = 0, 1065 }; 1066 time_t now = odhcpd_time(); 1067 1068 if (oaddr->preferred_lt) { 1069 int64_t preferred_lt = oaddr->preferred_lt - now; 1070 if (preferred_lt < 0) 1071 preferred_lt = 0; 1072 else if (preferred_lt > UINT32_MAX) 1073 preferred_lt = UINT32_MAX; 1074 1075 cinfo.ifa_prefered = preferred_lt; 1076 } 1077 1078 if (oaddr->valid_lt) { 1079 int64_t valid_lt = oaddr->valid_lt - now; 1080 if (valid_lt <= 0) { 1081 nlmsg_free(msg); 1082 return -1; 1083 } 1084 else if (valid_lt > UINT32_MAX) 1085 valid_lt = UINT32_MAX; 1086 1087 cinfo.ifa_valid = valid_lt; 1088 } 1089 1090 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo); 1091 1092 nla_put_u32(msg, IFA_FLAGS, IFA_F_NOPREFIXROUTE); 1093 } else { 1094 if (oaddr->broadcast.s_addr) 1095 nla_put_u32(msg, IFA_BROADCAST, oaddr->broadcast.s_addr); 1096 } 1097 1098 ret = nl_send_auto_complete(rtnl_socket, msg); 1099 nlmsg_free(msg); 1100 1101 if (ret < 0) 1102 return ret; 1103 1104 return nl_wait_for_ack(rtnl_socket); 1105 } 1106 1107 void netlink_dump_neigh_table(const bool proxy) 1108 { 1109 struct nl_msg *msg; 1110 struct ndmsg ndm = { 1111 .ndm_family = AF_INET6, 1112 .ndm_flags = proxy ? NTF_PROXY : 0, 1113 }; 1114 1115 msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP); 1116 if (!msg) 1117 return; 1118 1119 nlmsg_append(msg, &ndm, sizeof(ndm), 0); 1120 1121 nl_send_auto_complete(rtnl_event.sock, msg); 1122 1123 nlmsg_free(msg); 1124 } 1125 1126 void netlink_dump_addr_table(const bool v6) 1127 { 1128 struct nl_msg *msg; 1129 struct ifaddrmsg ifa = { 1130 .ifa_family = v6 ? AF_INET6 : AF_INET, 1131 }; 1132 1133 msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP); 1134 if (!msg) 1135 return; 1136 1137 nlmsg_append(msg, &ifa, sizeof(ifa), 0); 1138 1139 nl_send_auto_complete(rtnl_event.sock, msg); 1140 1141 nlmsg_free(msg); 1142 } 1143
This page was automatically generated by LXR 0.3.1. • OpenWrt