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