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