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