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