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