1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <err.h> 5 #include <errno.h> 6 7 #include <sys/bitcount.h> 8 #include <sys/param.h> 9 #include <sys/linker.h> 10 #include <sys/module.h> 11 #include <sys/socket.h> 12 #include <sys/sysctl.h> 13 #include <sys/time.h> 14 #include <sys/types.h> 15 16 #include <netinet/in.h> 17 #include <arpa/inet.h> 18 19 #include <net/ethernet.h> 20 #include <net/if.h> 21 #include <net/if_dl.h> 22 #include <net/if_types.h> 23 #include <netlink/netlink.h> 24 #include <netlink/netlink_route.h> 25 #include <netlink/netlink_snl.h> 26 #include <netlink/netlink_snl_route.h> 27 #include <netlink/netlink_snl_route_compat.h> 28 #include <netlink/netlink_snl_route_parsers.h> 29 30 const char *routename(struct sockaddr *); 31 const char *netname(struct sockaddr *); 32 void printb(int, const char *); 33 extern const char routeflags[]; 34 extern int verbose, debugonly; 35 36 int rtmsg_nl(int cmd, int rtm_flags, int fib, int rtm_addrs, struct sockaddr_storage *so, 37 struct rt_metrics *rt_metrics); 38 int flushroutes_fib_nl(int fib, int af); 39 void monitor_nl(int fib); 40 41 struct nl_helper; 42 struct snl_msg_info; 43 static void print_getmsg(struct nl_helper *h, struct nlmsghdr *hdr, 44 struct sockaddr *dst); 45 static void print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr, 46 struct snl_msg_info *cinfo); 47 48 #define s6_addr32 __u6_addr.__u6_addr32 49 #define bitcount32(x) __bitcount32((uint32_t)(x)) 50 static int 51 inet6_get_plen(const struct in6_addr *addr) 52 { 53 54 return (bitcount32(addr->s6_addr32[0]) + bitcount32(addr->s6_addr32[1]) + 55 bitcount32(addr->s6_addr32[2]) + bitcount32(addr->s6_addr32[3])); 56 } 57 58 static void 59 ip6_writemask(struct in6_addr *addr6, uint8_t mask) 60 { 61 uint32_t *cp; 62 63 for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 64 *cp++ = 0xFFFFFFFF; 65 if (mask > 0) 66 *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 67 } 68 69 static struct sockaddr * 70 get_netmask(struct snl_state *ss, int family, int plen) 71 { 72 if (family == AF_INET) { 73 if (plen == 32) 74 return (NULL); 75 76 struct sockaddr_in *sin = snl_allocz(ss, sizeof(*sin)); 77 78 sin->sin_len = sizeof(*sin); 79 sin->sin_family = family; 80 sin->sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0); 81 82 return (struct sockaddr *)sin; 83 } else if (family == AF_INET6) { 84 if (plen == 128) 85 return (NULL); 86 87 struct sockaddr_in6 *sin6 = snl_allocz(ss, sizeof(*sin6)); 88 89 sin6->sin6_len = sizeof(*sin6); 90 sin6->sin6_family = family; 91 ip6_writemask(&sin6->sin6_addr, plen); 92 93 return (struct sockaddr *)sin6; 94 } 95 return (NULL); 96 } 97 98 static void 99 nl_init_socket(struct snl_state *ss) 100 { 101 if (snl_init(ss, NETLINK_ROUTE)) 102 return; 103 104 if (modfind("netlink") == -1 && errno == ENOENT) { 105 /* Try to load */ 106 if (kldload("netlink") == -1) 107 err(1, "netlink is not loaded and load attempt failed"); 108 if (snl_init(ss, NETLINK_ROUTE)) 109 return; 110 } 111 112 err(1, "unable to open netlink socket"); 113 } 114 115 struct nl_helper { 116 struct snl_state ss_cmd; 117 }; 118 119 static void 120 nl_helper_init(struct nl_helper *h) 121 { 122 nl_init_socket(&h->ss_cmd); 123 } 124 125 static void 126 nl_helper_free(struct nl_helper *h) 127 { 128 snl_free(&h->ss_cmd); 129 } 130 131 static struct sockaddr * 132 get_addr(struct sockaddr_storage *so, int rtm_addrs, int addr_type) 133 { 134 struct sockaddr *sa = NULL; 135 136 if (rtm_addrs & (1 << addr_type)) 137 sa = (struct sockaddr *)&so[addr_type]; 138 return (sa); 139 } 140 141 static int 142 rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib, int rtm_addrs, 143 struct sockaddr_storage *so, struct rt_metrics *rt_metrics) 144 { 145 struct snl_state *ss = &h->ss_cmd; 146 struct snl_writer nw; 147 int nl_type = 0, nl_flags = 0; 148 149 snl_init_writer(ss, &nw); 150 151 switch (cmd) { 152 case RTSOCK_RTM_ADD: 153 nl_type = RTM_NEWROUTE; 154 nl_flags = NLM_F_CREATE | NLM_F_APPEND; /* Do append by default */ 155 break; 156 case RTSOCK_RTM_CHANGE: 157 nl_type = RTM_NEWROUTE; 158 nl_flags = NLM_F_REPLACE; 159 break; 160 case RTSOCK_RTM_DELETE: 161 nl_type = RTM_DELROUTE; 162 break; 163 case RTSOCK_RTM_GET: 164 nl_type = RTM_GETROUTE; 165 break; 166 default: 167 exit(1); 168 } 169 170 struct sockaddr *dst = get_addr(so, rtm_addrs, RTAX_DST); 171 struct sockaddr *mask = get_addr(so, rtm_addrs, RTAX_NETMASK); 172 struct sockaddr *gw = get_addr(so, rtm_addrs, RTAX_GATEWAY); 173 174 if (dst == NULL) 175 return (EINVAL); 176 177 struct nlmsghdr *hdr = snl_create_msg_request(&nw, nl_type); 178 hdr->nlmsg_flags |= nl_flags; 179 180 int plen = 0; 181 int rtm_type = RTN_UNICAST; 182 183 switch (dst->sa_family) { 184 case AF_INET: 185 { 186 struct sockaddr_in *mask4 = (struct sockaddr_in *)mask; 187 188 if ((rtm_flags & RTF_HOST) == 0 && mask4 != NULL) 189 plen = bitcount32(mask4->sin_addr.s_addr); 190 else 191 plen = 32; 192 break; 193 } 194 case AF_INET6: 195 { 196 struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; 197 198 if ((rtm_flags & RTF_HOST) == 0 && mask6 != NULL) 199 plen = inet6_get_plen(&mask6->sin6_addr); 200 else 201 plen = 128; 202 break; 203 } 204 default: 205 return (ENOTSUP); 206 } 207 208 if (rtm_flags & RTF_REJECT) 209 rtm_type = RTN_PROHIBIT; 210 else if (rtm_flags & RTF_BLACKHOLE) 211 rtm_type = RTN_BLACKHOLE; 212 213 struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg); 214 rtm->rtm_family = dst->sa_family; 215 rtm->rtm_protocol = RTPROT_STATIC; 216 rtm->rtm_type = rtm_type; 217 rtm->rtm_dst_len = plen; 218 219 /* Request exact prefix match if mask is set */ 220 if ((cmd == RTSOCK_RTM_GET) && (mask != NULL)) 221 rtm->rtm_flags = RTM_F_PREFIX; 222 223 snl_add_msg_attr_ip(&nw, RTA_DST, dst); 224 snl_add_msg_attr_u32(&nw, RTA_TABLE, fib); 225 226 uint32_t rta_oif = 0; 227 228 if (gw != NULL) { 229 if (rtm_flags & RTF_GATEWAY) { 230 if (gw->sa_family == dst->sa_family) 231 snl_add_msg_attr_ip(&nw, RTA_GATEWAY, gw); 232 else 233 snl_add_msg_attr_ipvia(&nw, RTA_VIA, gw); 234 if (gw->sa_family == AF_INET6) { 235 struct sockaddr_in6 *gw6 = (struct sockaddr_in6 *)gw; 236 237 if (IN6_IS_ADDR_LINKLOCAL(&gw6->sin6_addr)) 238 rta_oif = gw6->sin6_scope_id; 239 } 240 } else { 241 /* Should be AF_LINK */ 242 struct sockaddr_dl *sdl = (struct sockaddr_dl *)gw; 243 if (sdl->sdl_index != 0) 244 rta_oif = sdl->sdl_index; 245 } 246 } 247 248 if (dst->sa_family == AF_INET6 && rta_oif == 0) { 249 struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst; 250 251 if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) 252 rta_oif = dst6->sin6_scope_id; 253 } 254 255 if (rta_oif != 0) 256 snl_add_msg_attr_u32(&nw, RTA_OIF, rta_oif); 257 if (rtm_flags != 0) 258 snl_add_msg_attr_u32(&nw, NL_RTA_RTFLAGS, rtm_flags); 259 260 if (rt_metrics->rmx_mtu > 0) { 261 int off = snl_add_msg_attr_nested(&nw, RTA_METRICS); 262 snl_add_msg_attr_u32(&nw, RTAX_MTU, rt_metrics->rmx_mtu); 263 snl_end_attr_nested(&nw, off); 264 } 265 266 if (rt_metrics->rmx_weight > 0) 267 snl_add_msg_attr_u32(&nw, NL_RTA_WEIGHT, rt_metrics->rmx_weight); 268 269 if ((hdr = snl_finalize_msg(&nw)) && snl_send_message(ss, hdr)) { 270 struct snl_errmsg_data e = {}; 271 272 hdr = snl_read_reply(ss, hdr->nlmsg_seq); 273 if (nl_type == NL_RTM_GETROUTE) { 274 if (hdr->nlmsg_type == NL_RTM_NEWROUTE) { 275 print_getmsg(h, hdr, dst); 276 return (0); 277 } 278 } 279 280 if (snl_parse_errmsg(ss, hdr, &e)) { 281 switch (e.error) { 282 case (ESRCH): 283 warnx("route has not been found"); 284 break; 285 default: 286 if (e.error == 0) 287 break; 288 warnc(e.error, "message indicates error"); 289 } 290 291 return (e.error); 292 } 293 } 294 295 return (EINVAL); 296 } 297 298 int 299 rtmsg_nl(int cmd, int rtm_flags, int fib, int rtm_addrs, 300 struct sockaddr_storage *so, struct rt_metrics *rt_metrics) 301 { 302 struct nl_helper h = {}; 303 304 nl_helper_init(&h); 305 int error = rtmsg_nl_int(&h, cmd, rtm_flags, fib, rtm_addrs, so, rt_metrics); 306 nl_helper_free(&h); 307 308 return (error); 309 } 310 311 static void 312 get_ifdata(struct nl_helper *h, uint32_t ifindex, struct snl_parsed_link_simple *link) 313 { 314 struct snl_state *ss = &h->ss_cmd; 315 struct snl_writer nw; 316 317 snl_init_writer(ss, &nw); 318 struct nlmsghdr *hdr = snl_create_msg_request(&nw, NL_RTM_GETLINK); 319 struct ifinfomsg *ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg); 320 if (ifmsg != NULL) 321 ifmsg->ifi_index = ifindex; 322 if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 323 return; 324 325 hdr = snl_read_reply(ss, hdr->nlmsg_seq); 326 327 if (hdr != NULL && hdr->nlmsg_type == RTM_NEWLINK) { 328 snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, link); 329 } 330 331 if (link->ifla_ifname == NULL) { 332 char ifname[16]; 333 334 snprintf(ifname, sizeof(ifname), "if#%u", ifindex); 335 int len = strlen(ifname); 336 char *buf = snl_allocz(ss, len + 1); 337 strlcpy(buf, ifname, len + 1); 338 link->ifla_ifname = buf; 339 } 340 } 341 342 static void 343 print_getmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct sockaddr *dst) 344 { 345 struct snl_state *ss = &h->ss_cmd; 346 struct timespec ts; 347 struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT }; 348 349 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r)) 350 return; 351 352 struct snl_parsed_link_simple link = {}; 353 get_ifdata(h, r.rta_oif, &link); 354 355 if (r.rtax_mtu == 0) 356 r.rtax_mtu = link.ifla_mtu; 357 r.rta_rtflags |= (RTF_UP | RTF_DONE); 358 359 (void)printf(" route to: %s\n", routename(dst)); 360 361 if (r.rta_dst) 362 (void)printf("destination: %s\n", routename(r.rta_dst)); 363 struct sockaddr *mask = get_netmask(ss, r.rtm_family, r.rtm_dst_len); 364 if (mask) 365 (void)printf(" mask: %s\n", routename(mask)); 366 if (r.rta_gw && (r.rta_rtflags & RTF_GATEWAY)) 367 (void)printf(" gateway: %s\n", routename(r.rta_gw)); 368 (void)printf(" fib: %u\n", (unsigned int)r.rta_table); 369 if (link.ifla_ifname) 370 (void)printf(" interface: %s\n", link.ifla_ifname); 371 (void)printf(" flags: "); 372 printb(r.rta_rtflags, routeflags); 373 374 struct rt_metrics rmx = { 375 .rmx_mtu = r.rtax_mtu, 376 .rmx_weight = r.rtax_weight, 377 .rmx_expire = r.rta_expire, 378 }; 379 380 printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe", 381 "sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire"); 382 printf("%8lu ", rmx.rmx_recvpipe); 383 printf("%8lu ", rmx.rmx_sendpipe); 384 printf("%8lu ", rmx.rmx_ssthresh); 385 printf("%8lu ", 0UL); 386 printf("%8lu ", rmx.rmx_mtu); 387 printf("%8lu ", rmx.rmx_weight); 388 if (rmx.rmx_expire > 0) 389 clock_gettime(CLOCK_REALTIME_FAST, &ts); 390 else 391 ts.tv_sec = 0; 392 printf("%8ld \n", (long)(rmx.rmx_expire - ts.tv_sec)); 393 } 394 395 static void 396 print_prefix(struct nl_helper *h, char *buf, int bufsize, struct sockaddr *sa, int plen) 397 { 398 int sz = 0; 399 400 if (sa == NULL) { 401 snprintf(buf, bufsize, "<NULL>"); 402 return; 403 } 404 405 switch (sa->sa_family) { 406 case AF_INET: 407 { 408 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 409 char abuf[INET_ADDRSTRLEN]; 410 411 inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf)); 412 sz = snprintf(buf, bufsize, "%s", abuf); 413 break; 414 } 415 case AF_INET6: 416 { 417 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 418 char abuf[INET6_ADDRSTRLEN]; 419 char *ifname = NULL; 420 421 inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, sizeof(abuf)); 422 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 423 struct snl_parsed_link_simple link = {}; 424 425 if (sin6->sin6_scope_id != 0) { 426 get_ifdata(h, sin6->sin6_scope_id, &link); 427 ifname = link.ifla_ifname; 428 } 429 } 430 if (ifname == NULL) 431 sz = snprintf(buf, bufsize, "%s", abuf); 432 else 433 sz = snprintf(buf, bufsize, "%s%%%s", abuf, ifname); 434 break; 435 } 436 default: 437 snprintf(buf, bufsize, "unknown_af#%d", sa->sa_family); 438 plen = -1; 439 } 440 441 if (plen >= 0) 442 snprintf(buf + sz, bufsize - sz, "/%d", plen); 443 } 444 445 static int 446 print_line_prefix(struct nlmsghdr *hdr, struct snl_msg_info *cinfo, 447 const char *cmd, const char *name) 448 { 449 struct timespec tp; 450 struct tm tm; 451 char buf[32]; 452 453 clock_gettime(CLOCK_REALTIME, &tp); 454 localtime_r(&tp.tv_sec, &tm); 455 456 strftime(buf, sizeof(buf), "%T", &tm); 457 int len = printf("%s.%03ld PID %4u %s %s ", buf, tp.tv_nsec / 1000000, 458 cinfo->process_id, cmd, name); 459 460 return (len); 461 } 462 463 static const char * 464 get_action_name(struct nlmsghdr *hdr, int new_cmd) 465 { 466 if (hdr->nlmsg_type == new_cmd) { 467 //return ((hdr->nlmsg_flags & NLM_F_REPLACE) ? "replace" : "add"); 468 return ("add/repl"); 469 } else 470 return ("delete"); 471 } 472 473 static void 474 print_nlmsg_route_nhop(struct nl_helper *h, struct snl_parsed_route *r, 475 struct rta_mpath_nh *nh, bool first) 476 { 477 // gw 10.0.0.1 ifp vtnet0 mtu 1500 table inet.0 478 if (nh->gw != NULL) { 479 char gwbuf[128]; 480 print_prefix(h, gwbuf, sizeof(gwbuf), nh->gw, -1); 481 printf("gw %s ", gwbuf); 482 } 483 484 if (nh->ifindex != 0) { 485 struct snl_parsed_link_simple link = {}; 486 487 get_ifdata(h, nh->ifindex, &link); 488 if (nh->rtax_mtu == 0) 489 nh->rtax_mtu = link.ifla_mtu; 490 printf("iface %s ", link.ifla_ifname); 491 if (nh->rtax_mtu != 0) 492 printf("mtu %d ", nh->rtax_mtu); 493 } 494 495 if (first) { 496 switch (r->rtm_family) { 497 case AF_INET: 498 printf("table inet.%d", r->rta_table); 499 break; 500 case AF_INET6: 501 printf("table inet6.%d", r->rta_table); 502 break; 503 } 504 } 505 506 printf("\n"); 507 } 508 509 static void 510 print_nlmsg_route(struct nl_helper *h, struct nlmsghdr *hdr, 511 struct snl_msg_info *cinfo) 512 { 513 struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT }; 514 struct snl_state *ss = &h->ss_cmd; 515 516 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r)) 517 return; 518 519 // 20:19:41.333 add route 10.0.0.0/24 gw 10.0.0.1 ifp vtnet0 mtu 1500 table inet.0 520 521 const char *cmd = get_action_name(hdr, RTM_NEWROUTE); 522 int len = print_line_prefix(hdr, cinfo, cmd, "route"); 523 524 char buf[128]; 525 print_prefix(h, buf, sizeof(buf), r.rta_dst, r.rtm_dst_len); 526 len += strlen(buf) + 1; 527 printf("%s ", buf); 528 529 switch (r.rtm_type) { 530 case RTN_BLACKHOLE: 531 printf("blackhole\n"); 532 return; 533 case RTN_UNREACHABLE: 534 printf("unreach(reject)\n"); 535 return; 536 case RTN_PROHIBIT: 537 printf("prohibit(reject)\n"); 538 return; 539 } 540 541 if (r.rta_multipath.num_nhops != 0) { 542 bool first = true; 543 544 memset(buf, ' ', sizeof(buf)); 545 buf[len] = '\0'; 546 547 for (uint32_t i = 0; i < r.rta_multipath.num_nhops; i++) { 548 struct rta_mpath_nh *nh = r.rta_multipath.nhops[i]; 549 550 if (!first) 551 printf("%s", buf); 552 print_nlmsg_route_nhop(h, &r, nh, first); 553 first = false; 554 } 555 } else { 556 struct rta_mpath_nh nh = { 557 .gw = r.rta_gw, 558 .ifindex = r.rta_oif, 559 .rtax_mtu = r.rtax_mtu, 560 }; 561 562 print_nlmsg_route_nhop(h, &r, &nh, true); 563 } 564 } 565 566 static const char *operstate[] = { 567 "UNKNOWN", /* 0, IF_OPER_UNKNOWN */ 568 "NOTPRESENT", /* 1, IF_OPER_NOTPRESENT */ 569 "DOWN", /* 2, IF_OPER_DOWN */ 570 "LLDOWN", /* 3, IF_OPER_LOWERLAYERDOWN */ 571 "TESTING", /* 4, IF_OPER_TESTING */ 572 "DORMANT", /* 5, IF_OPER_DORMANT */ 573 "UP", /* 6, IF_OPER_UP */ 574 }; 575 576 static void 577 print_nlmsg_link(struct nl_helper *h, struct nlmsghdr *hdr, 578 struct snl_msg_info *cinfo) 579 { 580 struct snl_parsed_link l = {}; 581 struct snl_state *ss = &h->ss_cmd; 582 583 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser, &l)) 584 return; 585 586 // 20:19:41.333 add iface#3 vtnet0 admin UP oper UP mtu 1500 table inet.0 587 const char *cmd = get_action_name(hdr, RTM_NEWLINK); 588 print_line_prefix(hdr, cinfo, cmd, "iface"); 589 590 printf("iface#%u %s ", l.ifi_index, l.ifla_ifname); 591 printf("admin %s ", (l.ifi_flags & IFF_UP) ? "UP" : "DOWN"); 592 if (l.ifla_operstate < NL_ARRAY_LEN(operstate)) 593 printf("oper %s ", operstate[l.ifla_operstate]); 594 if (l.ifla_mtu > 0) 595 printf("mtu %u ", l.ifla_mtu); 596 597 printf("\n"); 598 } 599 600 static void 601 print_nlmsg_addr(struct nl_helper *h, struct nlmsghdr *hdr, 602 struct snl_msg_info *cinfo) 603 { 604 struct snl_parsed_addr attrs = {}; 605 struct snl_state *ss = &h->ss_cmd; 606 607 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &attrs)) 608 return; 609 610 // add addr 192.168.1.1/24 iface vtnet0 611 const char *cmd = get_action_name(hdr, RTM_NEWADDR); 612 print_line_prefix(hdr, cinfo, cmd, "addr"); 613 614 char buf[128]; 615 struct sockaddr *addr = attrs.ifa_local ? attrs.ifa_local : attrs.ifa_address; 616 print_prefix(h, buf, sizeof(buf), addr, attrs.ifa_prefixlen); 617 printf("%s ", buf); 618 619 struct snl_parsed_link_simple link = {}; 620 get_ifdata(h, attrs.ifa_index, &link); 621 622 if (link.ifi_flags & IFF_POINTOPOINT) { 623 char buf[64]; 624 print_prefix(h, buf, sizeof(buf), attrs.ifa_address, -1); 625 printf("-> %s ", buf); 626 } 627 628 printf("iface %s ", link.ifla_ifname); 629 630 printf("\n"); 631 } 632 633 static const char *nudstate[] = { 634 "INCOMPLETE", /* 0x01(0) */ 635 "REACHABLE", /* 0x02(1) */ 636 "STALE", /* 0x04(2) */ 637 "DELAY", /* 0x08(3) */ 638 "PROBE", /* 0x10(4) */ 639 "FAILED", /* 0x20(5) */ 640 }; 641 642 #define NUD_INCOMPLETE 0x01 /* No lladdr, address resolution in progress */ 643 #define NUD_REACHABLE 0x02 /* reachable & recently resolved */ 644 #define NUD_STALE 0x04 /* has lladdr but it's stale */ 645 #define NUD_DELAY 0x08 /* has lladdr, is stale, probes delayed */ 646 #define NUD_PROBE 0x10 /* has lladdr, is stale, probes sent */ 647 #define NUD_FAILED 0x20 /* unused */ 648 649 650 static void 651 print_nlmsg_neigh(struct nl_helper *h, struct nlmsghdr *hdr, 652 struct snl_msg_info *cinfo) 653 { 654 struct snl_parsed_neigh attrs = {}; 655 struct snl_state *ss = &h->ss_cmd; 656 657 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_neigh_parser, &attrs)) 658 return; 659 660 // add addr 192.168.1.1 state %s lladdr %s iface vtnet0 661 const char *cmd = get_action_name(hdr, RTM_NEWNEIGH); 662 print_line_prefix(hdr, cinfo, cmd, "neigh"); 663 664 char buf[128]; 665 print_prefix(h, buf, sizeof(buf), attrs.nda_dst, -1); 666 printf("%s ", buf); 667 668 struct snl_parsed_link_simple link = {}; 669 get_ifdata(h, attrs.nda_ifindex, &link); 670 671 for (unsigned int i = 0; i < NL_ARRAY_LEN(nudstate); i++) { 672 if ((1 << i) & attrs.ndm_state) { 673 printf("state %s ", nudstate[i]); 674 break; 675 } 676 } 677 678 if (attrs.nda_lladdr != NULL) { 679 int if_type = link.ifi_type; 680 681 if ((if_type == IFT_ETHER || if_type == IFT_L2VLAN || if_type == IFT_BRIDGE) && 682 NLA_DATA_LEN(attrs.nda_lladdr) == ETHER_ADDR_LEN) { 683 struct ether_addr *ll; 684 685 ll = (struct ether_addr *)NLA_DATA(attrs.nda_lladdr); 686 printf("lladdr %s ", ether_ntoa(ll)); 687 } else { 688 struct sockaddr_dl sdl = { 689 .sdl_len = sizeof(sdl), 690 .sdl_family = AF_LINK, 691 .sdl_index = attrs.nda_ifindex, 692 .sdl_type = if_type, 693 .sdl_alen = NLA_DATA_LEN(attrs.nda_lladdr), 694 }; 695 if (sdl.sdl_alen < sizeof(sdl.sdl_data)) { 696 void *ll = NLA_DATA(attrs.nda_lladdr); 697 698 memcpy(sdl.sdl_data, ll, sdl.sdl_alen); 699 printf("lladdr %s ", link_ntoa(&sdl)); 700 } 701 } 702 } 703 704 if (link.ifla_ifname != NULL) 705 printf("iface %s ", link.ifla_ifname); 706 printf("\n"); 707 } 708 709 static void 710 print_nlmsg_generic(struct nl_helper *h, struct nlmsghdr *hdr, struct snl_msg_info *cinfo) 711 { 712 const char *cmd = get_action_name(hdr, 0); 713 print_line_prefix(hdr, cinfo, cmd, "unknown message"); 714 printf(" type %u\n", hdr->nlmsg_type); 715 } 716 717 static void 718 print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct snl_msg_info *cinfo) 719 { 720 switch (hdr->nlmsg_type) { 721 case RTM_NEWLINK: 722 case RTM_DELLINK: 723 print_nlmsg_link(h, hdr, cinfo); 724 break; 725 case RTM_NEWADDR: 726 case RTM_DELADDR: 727 print_nlmsg_addr(h, hdr, cinfo); 728 break; 729 case RTM_NEWROUTE: 730 case RTM_DELROUTE: 731 print_nlmsg_route(h, hdr, cinfo); 732 break; 733 case RTM_NEWNEIGH: 734 case RTM_DELNEIGH: 735 print_nlmsg_neigh(h, hdr, cinfo); 736 break; 737 default: 738 print_nlmsg_generic(h, hdr, cinfo); 739 } 740 741 snl_clear_lb(&h->ss_cmd); 742 } 743 744 void 745 monitor_nl(int fib) 746 { 747 struct snl_state ss_event = {}; 748 struct nl_helper h; 749 750 nl_init_socket(&ss_event); 751 nl_helper_init(&h); 752 753 int groups[] = { 754 RTNLGRP_LINK, 755 RTNLGRP_NEIGH, 756 RTNLGRP_NEXTHOP, 757 #ifdef INET 758 RTNLGRP_IPV4_IFADDR, 759 RTNLGRP_IPV4_ROUTE, 760 #endif 761 #ifdef INET6 762 RTNLGRP_IPV6_IFADDR, 763 RTNLGRP_IPV6_ROUTE, 764 #endif 765 }; 766 767 int optval = 1; 768 socklen_t optlen = sizeof(optval); 769 setsockopt(ss_event.fd, SOL_NETLINK, NETLINK_MSG_INFO, &optval, optlen); 770 771 for (unsigned int i = 0; i < NL_ARRAY_LEN(groups); i++) { 772 int error; 773 int optval = groups[i]; 774 socklen_t optlen = sizeof(optval); 775 error = setsockopt(ss_event.fd, SOL_NETLINK, 776 NETLINK_ADD_MEMBERSHIP, &optval, optlen); 777 if (error != 0) 778 warn("Unable to subscribe to group %d", optval); 779 } 780 781 struct snl_msg_info attrs = {}; 782 struct nlmsghdr *hdr; 783 while ((hdr = snl_read_message_dbg(&ss_event, &attrs)) != NULL) 784 { 785 print_nlmsg(&h, hdr, &attrs); 786 snl_clear_lb(&h.ss_cmd); 787 snl_clear_lb(&ss_event); 788 } 789 790 snl_free(&ss_event); 791 nl_helper_free(&h); 792 exit(0); 793 } 794 795 static void 796 print_flushed_route(struct snl_parsed_route *r, struct sockaddr *gw) 797 { 798 struct sockaddr *sa = r->rta_dst; 799 800 printf("%-20.20s ", r->rta_rtflags & RTF_HOST ? 801 routename(sa) : netname(sa)); 802 sa = gw; 803 printf("%-20.20s ", routename(sa)); 804 printf("-fib %-3d ", r->rta_table); 805 printf("done\n"); 806 } 807 808 static int 809 flushroute_one(struct nl_helper *h, struct snl_parsed_route *r) 810 { 811 struct snl_state *ss = &h->ss_cmd; 812 struct snl_errmsg_data e = {}; 813 struct snl_writer nw; 814 815 snl_init_writer(ss, &nw); 816 817 struct nlmsghdr *hdr = snl_create_msg_request(&nw, NL_RTM_DELROUTE); 818 struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg); 819 rtm->rtm_family = r->rtm_family; 820 rtm->rtm_dst_len = r->rtm_dst_len; 821 822 snl_add_msg_attr_u32(&nw, RTA_TABLE, r->rta_table); 823 snl_add_msg_attr_ip(&nw, RTA_DST, r->rta_dst); 824 825 if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 826 return (ENOMEM); 827 828 if (!snl_read_reply_code(ss, hdr->nlmsg_seq, &e)) { 829 return (e.error); 830 if (e.error == EPERM) 831 errc(1, e.error, "RTM_DELROUTE failed:"); 832 else 833 warnc(e.error, "RTM_DELROUTE failed:"); 834 return (true); 835 }; 836 837 if (verbose) { 838 struct snl_msg_info attrs = {}; 839 print_nlmsg(h, hdr, &attrs); 840 } 841 else { 842 if (r->rta_multipath.num_nhops != 0) { 843 for (uint32_t i = 0; i < r->rta_multipath.num_nhops; i++) { 844 struct rta_mpath_nh *nh = r->rta_multipath.nhops[i]; 845 846 print_flushed_route(r, nh->gw); 847 } 848 849 } else 850 print_flushed_route(r, r->rta_gw); 851 } 852 853 return (0); 854 } 855 856 int 857 flushroutes_fib_nl(int fib, int af) 858 { 859 struct snl_state ss = {}; 860 struct snl_writer nw; 861 struct nl_helper h = {}; 862 863 nl_init_socket(&ss); 864 snl_init_writer(&ss, &nw); 865 866 struct nlmsghdr *hdr = snl_create_msg_request(&nw, NL_RTM_GETROUTE); 867 hdr->nlmsg_flags |= NLM_F_DUMP; 868 struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg); 869 rtm->rtm_family = af; 870 snl_add_msg_attr_u32(&nw, RTA_TABLE, fib); 871 872 if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(&ss, hdr)) { 873 snl_free(&ss); 874 return (EINVAL); 875 } 876 877 struct snl_errmsg_data e = {}; 878 uint32_t nlm_seq = hdr->nlmsg_seq; 879 880 nl_helper_init(&h); 881 882 while ((hdr = snl_read_reply_multi(&ss, nlm_seq, &e)) != NULL) { 883 struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT }; 884 int error; 885 886 if (!snl_parse_nlmsg(&ss, hdr, &snl_rtm_route_parser, &r)) 887 continue; 888 if (verbose) { 889 struct snl_msg_info attrs = {}; 890 print_nlmsg(&h, hdr, &attrs); 891 } 892 if (r.rta_table != (uint32_t)fib || r.rtm_family != af) 893 continue; 894 if ((r.rta_rtflags & RTF_GATEWAY) == 0) 895 continue; 896 if (debugonly) 897 continue; 898 899 if ((error = flushroute_one(&h, &r)) != 0) { 900 if (error == EPERM) 901 errc(1, error, "RTM_DELROUTE failed:"); 902 else 903 warnc(error, "RTM_DELROUTE failed:"); 904 } 905 snl_clear_lb(&h.ss_cmd); 906 } 907 908 snl_free(&ss); 909 nl_helper_free(&h); 910 911 return (e.error); 912 } 913 914