191fbe081SAlexander V. Chernikov #include <sys/param.h> 291fbe081SAlexander V. Chernikov #include <sys/module.h> 391fbe081SAlexander V. Chernikov #include <sys/file.h> 491fbe081SAlexander V. Chernikov #include <sys/ioctl.h> 591fbe081SAlexander V. Chernikov #include <sys/linker.h> 691fbe081SAlexander V. Chernikov #include <sys/socket.h> 791fbe081SAlexander V. Chernikov #include <sys/sysctl.h> 891fbe081SAlexander V. Chernikov #include <sys/time.h> 991fbe081SAlexander V. Chernikov #include <sys/queue.h> 1091fbe081SAlexander V. Chernikov 1191fbe081SAlexander V. Chernikov #include <net/if.h> 1291fbe081SAlexander V. Chernikov #include <net/if_dl.h> 1391fbe081SAlexander V. Chernikov #include <net/if_types.h> 1491fbe081SAlexander V. Chernikov 1591fbe081SAlexander V. Chernikov #include <netinet/in.h> 1691fbe081SAlexander V. Chernikov #include <netinet/if_ether.h> 1791fbe081SAlexander V. Chernikov 1891fbe081SAlexander V. Chernikov #include <netinet/icmp6.h> 1991fbe081SAlexander V. Chernikov #include <netinet6/in6_var.h> 2091fbe081SAlexander V. Chernikov #include <netinet6/nd6.h> 2191fbe081SAlexander V. Chernikov 2291fbe081SAlexander V. Chernikov #include <arpa/inet.h> 2391fbe081SAlexander V. Chernikov 2491fbe081SAlexander V. Chernikov #include <ctype.h> 2591fbe081SAlexander V. Chernikov #include <netdb.h> 2691fbe081SAlexander V. Chernikov #include <errno.h> 2791fbe081SAlexander V. Chernikov #include <nlist.h> 2891fbe081SAlexander V. Chernikov #include <stdio.h> 2991fbe081SAlexander V. Chernikov #include <string.h> 3091fbe081SAlexander V. Chernikov #include <paths.h> 3191fbe081SAlexander V. Chernikov #include <stdlib.h> 3291fbe081SAlexander V. Chernikov #include <fcntl.h> 3391fbe081SAlexander V. Chernikov #include <unistd.h> 3491fbe081SAlexander V. Chernikov #include <libxo/xo.h> 3591fbe081SAlexander V. Chernikov 3691fbe081SAlexander V. Chernikov 3791fbe081SAlexander V. Chernikov #include <netlink/netlink.h> 3891fbe081SAlexander V. Chernikov #include <netlink/netlink_route.h> 3991fbe081SAlexander V. Chernikov #include <netlink/netlink_snl.h> 4091fbe081SAlexander V. Chernikov #include <netlink/netlink_snl_route.h> 4191fbe081SAlexander V. Chernikov #include <netlink/netlink_snl_route_compat.h> 4291fbe081SAlexander V. Chernikov #include <netlink/netlink_snl_route_parsers.h> 4391fbe081SAlexander V. Chernikov 4491fbe081SAlexander V. Chernikov #include "ndp.h" 4591fbe081SAlexander V. Chernikov 4691fbe081SAlexander V. Chernikov #define RTF_ANNOUNCE RTF_PROTO2 4791fbe081SAlexander V. Chernikov 4891fbe081SAlexander V. Chernikov static void 4991fbe081SAlexander V. Chernikov nl_init_socket(struct snl_state *ss) 5091fbe081SAlexander V. Chernikov { 5191fbe081SAlexander V. Chernikov if (snl_init(ss, NETLINK_ROUTE)) 5291fbe081SAlexander V. Chernikov return; 5391fbe081SAlexander V. Chernikov 5491fbe081SAlexander V. Chernikov if (modfind("netlink") == -1 && errno == ENOENT) { 5591fbe081SAlexander V. Chernikov /* Try to load */ 5691fbe081SAlexander V. Chernikov if (kldload("netlink") == -1) 5754ff53d8SYan-Hao Wang xo_err(1, "netlink is not loaded and load attempt failed"); 5891fbe081SAlexander V. Chernikov if (snl_init(ss, NETLINK_ROUTE)) 5991fbe081SAlexander V. Chernikov return; 6091fbe081SAlexander V. Chernikov } 6191fbe081SAlexander V. Chernikov 6254ff53d8SYan-Hao Wang xo_err(1, "unable to open netlink socket"); 6391fbe081SAlexander V. Chernikov } 6491fbe081SAlexander V. Chernikov 6591fbe081SAlexander V. Chernikov static bool 6691fbe081SAlexander V. Chernikov get_link_info(struct snl_state *ss, uint32_t ifindex, 6791fbe081SAlexander V. Chernikov struct snl_parsed_link_simple *link) 6891fbe081SAlexander V. Chernikov { 6991fbe081SAlexander V. Chernikov struct snl_writer nw; 7091fbe081SAlexander V. Chernikov 7191fbe081SAlexander V. Chernikov snl_init_writer(ss, &nw); 7291fbe081SAlexander V. Chernikov 7391fbe081SAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 7491fbe081SAlexander V. Chernikov struct ifinfomsg *ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg); 7591fbe081SAlexander V. Chernikov if (ifmsg != NULL) 7691fbe081SAlexander V. Chernikov ifmsg->ifi_index = ifindex; 774f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 7891fbe081SAlexander V. Chernikov return (false); 7991fbe081SAlexander V. Chernikov 8091fbe081SAlexander V. Chernikov hdr = snl_read_reply(ss, hdr->nlmsg_seq); 8191fbe081SAlexander V. Chernikov 8291fbe081SAlexander V. Chernikov if (hdr == NULL || hdr->nlmsg_type != RTM_NEWLINK) 8391fbe081SAlexander V. Chernikov return (false); 8491fbe081SAlexander V. Chernikov 8591fbe081SAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, link)) 8691fbe081SAlexander V. Chernikov return (false); 8791fbe081SAlexander V. Chernikov 8891fbe081SAlexander V. Chernikov return (true); 8991fbe081SAlexander V. Chernikov } 9091fbe081SAlexander V. Chernikov 9191fbe081SAlexander V. Chernikov 9291fbe081SAlexander V. Chernikov 9391fbe081SAlexander V. Chernikov static bool 9491fbe081SAlexander V. Chernikov has_l2(struct snl_state *ss, uint32_t ifindex) 9591fbe081SAlexander V. Chernikov { 9691fbe081SAlexander V. Chernikov struct snl_parsed_link_simple link = {}; 9791fbe081SAlexander V. Chernikov 9891fbe081SAlexander V. Chernikov if (!get_link_info(ss, ifindex, &link)) 9991fbe081SAlexander V. Chernikov return (false); 10091fbe081SAlexander V. Chernikov 10191fbe081SAlexander V. Chernikov return (valid_type(link.ifi_type) != 0); 10291fbe081SAlexander V. Chernikov } 10391fbe081SAlexander V. Chernikov 10491fbe081SAlexander V. Chernikov static uint32_t 1052d7842d0SJohn Baldwin get_myfib(void) 10691fbe081SAlexander V. Chernikov { 10791fbe081SAlexander V. Chernikov uint32_t fibnum = 0; 10891fbe081SAlexander V. Chernikov size_t len = sizeof(fibnum); 10991fbe081SAlexander V. Chernikov 11091fbe081SAlexander V. Chernikov sysctlbyname("net.my_fibnum", (void *)&fibnum, &len, NULL, 0); 11191fbe081SAlexander V. Chernikov 11291fbe081SAlexander V. Chernikov return (fibnum); 11391fbe081SAlexander V. Chernikov } 11491fbe081SAlexander V. Chernikov 11591fbe081SAlexander V. Chernikov static void 11691fbe081SAlexander V. Chernikov ip6_writemask(struct in6_addr *addr6, uint8_t mask) 11791fbe081SAlexander V. Chernikov { 11891fbe081SAlexander V. Chernikov uint32_t *cp; 11991fbe081SAlexander V. Chernikov 12091fbe081SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 12191fbe081SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 12291fbe081SAlexander V. Chernikov if (mask > 0) 12391fbe081SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 12491fbe081SAlexander V. Chernikov } 12591fbe081SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 12691fbe081SAlexander V. Chernikov #define IN6_MASK_ADDR(a, m) do { \ 12791fbe081SAlexander V. Chernikov (a)->s6_addr32[0] &= (m)->s6_addr32[0]; \ 12891fbe081SAlexander V. Chernikov (a)->s6_addr32[1] &= (m)->s6_addr32[1]; \ 12991fbe081SAlexander V. Chernikov (a)->s6_addr32[2] &= (m)->s6_addr32[2]; \ 13091fbe081SAlexander V. Chernikov (a)->s6_addr32[3] &= (m)->s6_addr32[3]; \ 13191fbe081SAlexander V. Chernikov } while (0) 13291fbe081SAlexander V. Chernikov 13391fbe081SAlexander V. Chernikov static int 13491fbe081SAlexander V. Chernikov guess_ifindex(struct snl_state *ss, uint32_t fibnum, const struct sockaddr_in6 *dst) 13591fbe081SAlexander V. Chernikov { 13691fbe081SAlexander V. Chernikov struct snl_writer nw; 13791fbe081SAlexander V. Chernikov 13891fbe081SAlexander V. Chernikov if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr)) 13991fbe081SAlexander V. Chernikov return (dst->sin6_scope_id); 14091fbe081SAlexander V. Chernikov else if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) 14191fbe081SAlexander V. Chernikov return (0); 14291fbe081SAlexander V. Chernikov 14391fbe081SAlexander V. Chernikov 14491fbe081SAlexander V. Chernikov snl_init_writer(ss, &nw); 14591fbe081SAlexander V. Chernikov 14691fbe081SAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETROUTE); 14791fbe081SAlexander V. Chernikov struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg); 14891fbe081SAlexander V. Chernikov rtm->rtm_family = AF_INET6; 14991fbe081SAlexander V. Chernikov 15091fbe081SAlexander V. Chernikov snl_add_msg_attr_ip(&nw, RTA_DST, (struct sockaddr *)dst); 15191fbe081SAlexander V. Chernikov snl_add_msg_attr_u32(&nw, RTA_TABLE, fibnum); 15291fbe081SAlexander V. Chernikov 1534f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 15491fbe081SAlexander V. Chernikov return (0); 15591fbe081SAlexander V. Chernikov 15691fbe081SAlexander V. Chernikov hdr = snl_read_reply(ss, hdr->nlmsg_seq); 15791fbe081SAlexander V. Chernikov 15891fbe081SAlexander V. Chernikov if (hdr->nlmsg_type != NL_RTM_NEWROUTE) { 15991fbe081SAlexander V. Chernikov /* No route found, unable to guess ifindex */ 16091fbe081SAlexander V. Chernikov return (0); 16191fbe081SAlexander V. Chernikov } 16291fbe081SAlexander V. Chernikov 16391fbe081SAlexander V. Chernikov struct snl_parsed_route r = {}; 16491fbe081SAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r)) 16591fbe081SAlexander V. Chernikov return (0); 16691fbe081SAlexander V. Chernikov 167c9090124SAlexander V. Chernikov if (r.rta_multipath.num_nhops > 0 || (r.rta_rtflags & RTF_GATEWAY)) 16891fbe081SAlexander V. Chernikov return (0); 16991fbe081SAlexander V. Chernikov 17091fbe081SAlexander V. Chernikov /* Check if the interface is of supported type */ 17191fbe081SAlexander V. Chernikov if (has_l2(ss, r.rta_oif)) 17291fbe081SAlexander V. Chernikov return (r.rta_oif); 17391fbe081SAlexander V. Chernikov 17491fbe081SAlexander V. Chernikov /* Check the case when we matched the loopback route for P2P */ 17591fbe081SAlexander V. Chernikov snl_init_writer(ss, &nw); 17691fbe081SAlexander V. Chernikov hdr = snl_create_msg_request(&nw, RTM_GETNEXTHOP); 17791fbe081SAlexander V. Chernikov snl_reserve_msg_object(&nw, struct nhmsg); 17891fbe081SAlexander V. Chernikov 17991fbe081SAlexander V. Chernikov int off = snl_add_msg_attr_nested(&nw, NHA_FREEBSD); 18091fbe081SAlexander V. Chernikov snl_add_msg_attr_u32(&nw, NHAF_KID, r.rta_knh_id); 181934a24e5SR. Christian McDonald snl_add_msg_attr_u8(&nw, NHAF_FAMILY, AF_INET6); 18291fbe081SAlexander V. Chernikov snl_add_msg_attr_u32(&nw, NHAF_TABLE, fibnum); 18391fbe081SAlexander V. Chernikov snl_end_attr_nested(&nw, off); 18491fbe081SAlexander V. Chernikov 1854f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 18691fbe081SAlexander V. Chernikov return (0); 18791fbe081SAlexander V. Chernikov 18891fbe081SAlexander V. Chernikov hdr = snl_read_reply(ss, hdr->nlmsg_seq); 18991fbe081SAlexander V. Chernikov 19091fbe081SAlexander V. Chernikov if (hdr->nlmsg_type != NL_RTM_NEWNEXTHOP) { 19191fbe081SAlexander V. Chernikov /* No nexthop found, unable to guess ifindex */ 19291fbe081SAlexander V. Chernikov return (0); 19391fbe081SAlexander V. Chernikov } 19491fbe081SAlexander V. Chernikov 19591fbe081SAlexander V. Chernikov struct snl_parsed_nhop nh = {}; 19691fbe081SAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_nhmsg_parser, &nh)) 19791fbe081SAlexander V. Chernikov return (0); 19891fbe081SAlexander V. Chernikov 19991fbe081SAlexander V. Chernikov return (nh.nhaf_aif); 20091fbe081SAlexander V. Chernikov } 20191fbe081SAlexander V. Chernikov 20291fbe081SAlexander V. Chernikov static uint32_t 20391fbe081SAlexander V. Chernikov fix_ifindex(struct snl_state *ss, uint32_t ifindex, const struct sockaddr_in6 *sa) 20491fbe081SAlexander V. Chernikov { 20591fbe081SAlexander V. Chernikov if (ifindex == 0) 20691fbe081SAlexander V. Chernikov ifindex = guess_ifindex(ss, get_myfib(), sa); 20791fbe081SAlexander V. Chernikov return (ifindex); 20891fbe081SAlexander V. Chernikov } 20991fbe081SAlexander V. Chernikov 21091fbe081SAlexander V. Chernikov static void 21191fbe081SAlexander V. Chernikov print_entry(struct snl_parsed_neigh *neigh, struct snl_parsed_link_simple *link) 21291fbe081SAlexander V. Chernikov { 21391fbe081SAlexander V. Chernikov struct timeval now; 21491fbe081SAlexander V. Chernikov char host_buf[NI_MAXHOST]; 21591fbe081SAlexander V. Chernikov int addrwidth; 21691fbe081SAlexander V. Chernikov int llwidth; 21791fbe081SAlexander V. Chernikov int ifwidth; 21891fbe081SAlexander V. Chernikov char *ifname; 21991fbe081SAlexander V. Chernikov 22091fbe081SAlexander V. Chernikov getnameinfo(neigh->nda_dst, sizeof(struct sockaddr_in6), host_buf, 22191fbe081SAlexander V. Chernikov sizeof(host_buf), NULL, 0, (opts.nflag ? NI_NUMERICHOST : 0)); 22291fbe081SAlexander V. Chernikov 22391fbe081SAlexander V. Chernikov gettimeofday(&now, 0); 22491fbe081SAlexander V. Chernikov if (opts.tflag) 22591fbe081SAlexander V. Chernikov ts_print(&now); 22691fbe081SAlexander V. Chernikov 22791fbe081SAlexander V. Chernikov struct sockaddr_dl sdl = { 22891fbe081SAlexander V. Chernikov .sdl_family = AF_LINK, 22991fbe081SAlexander V. Chernikov .sdl_type = link->ifi_type, 23091fbe081SAlexander V. Chernikov .sdl_len = sizeof(struct sockaddr_dl), 23191fbe081SAlexander V. Chernikov }; 232b57df6fbSKristof Provost 233b57df6fbSKristof Provost if (neigh->nda_lladdr) { 234b57df6fbSKristof Provost sdl.sdl_alen = NLA_DATA_LEN(neigh->nda_lladdr), 23591fbe081SAlexander V. Chernikov memcpy(sdl.sdl_data, NLA_DATA(neigh->nda_lladdr), sdl.sdl_alen); 236b57df6fbSKristof Provost } 23791fbe081SAlexander V. Chernikov 23891fbe081SAlexander V. Chernikov addrwidth = strlen(host_buf); 23991fbe081SAlexander V. Chernikov if (addrwidth < W_ADDR) 24091fbe081SAlexander V. Chernikov addrwidth = W_ADDR; 24191fbe081SAlexander V. Chernikov llwidth = strlen(ether_str(&sdl)); 24291fbe081SAlexander V. Chernikov if (W_ADDR + W_LL - addrwidth > llwidth) 24391fbe081SAlexander V. Chernikov llwidth = W_ADDR + W_LL - addrwidth; 24491fbe081SAlexander V. Chernikov ifname = link->ifla_ifname; 24591fbe081SAlexander V. Chernikov ifwidth = strlen(ifname); 24691fbe081SAlexander V. Chernikov if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) 24791fbe081SAlexander V. Chernikov ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; 24891fbe081SAlexander V. Chernikov 24991fbe081SAlexander V. Chernikov xo_open_instance("neighbor-cache"); 25091fbe081SAlexander V. Chernikov /* Compose format string for libxo, as it doesn't support *.* */ 25191fbe081SAlexander V. Chernikov char xobuf[200]; 25291fbe081SAlexander V. Chernikov snprintf(xobuf, sizeof(xobuf), 25391fbe081SAlexander V. Chernikov "{:address/%%-%d.%ds/%%s} {:mac-address/%%-%d.%ds/%%s} {:interface/%%%d.%ds/%%s}", 25491fbe081SAlexander V. Chernikov addrwidth, addrwidth, llwidth, llwidth, ifwidth, ifwidth); 25591fbe081SAlexander V. Chernikov xo_emit(xobuf, host_buf, ether_str(&sdl), ifname); 25691fbe081SAlexander V. Chernikov 25791fbe081SAlexander V. Chernikov /* Print neighbor discovery specific information */ 2587825619aSAlexander V. Chernikov time_t expire = (time_t)neigh->ndaf_next_ts; 25991fbe081SAlexander V. Chernikov int expire_in = expire - now.tv_sec; 26091fbe081SAlexander V. Chernikov if (expire > now.tv_sec) 26191fbe081SAlexander V. Chernikov xo_emit("{d:/ %-9.9s}{e:expires_sec/%d}", sec2str(expire_in), expire_in); 26291fbe081SAlexander V. Chernikov else if (expire == 0) 26391fbe081SAlexander V. Chernikov xo_emit("{d:/ %-9.9s}{en:permanent/true}", "permanent"); 26491fbe081SAlexander V. Chernikov else 26591fbe081SAlexander V. Chernikov xo_emit("{d:/ %-9.9s}{e:expires_sec/%d}", "expired", expire_in); 26691fbe081SAlexander V. Chernikov 26791fbe081SAlexander V. Chernikov const char *lle_state = ""; 26891fbe081SAlexander V. Chernikov switch (neigh->ndm_state) { 26991fbe081SAlexander V. Chernikov case NUD_INCOMPLETE: 27091fbe081SAlexander V. Chernikov lle_state = "I"; 27191fbe081SAlexander V. Chernikov break; 27291fbe081SAlexander V. Chernikov case NUD_REACHABLE: 27391fbe081SAlexander V. Chernikov lle_state = "R"; 27491fbe081SAlexander V. Chernikov break; 27591fbe081SAlexander V. Chernikov case NUD_STALE: 27691fbe081SAlexander V. Chernikov lle_state = "S"; 27791fbe081SAlexander V. Chernikov break; 27891fbe081SAlexander V. Chernikov case NUD_DELAY: 27991fbe081SAlexander V. Chernikov lle_state = "D"; 28091fbe081SAlexander V. Chernikov break; 28191fbe081SAlexander V. Chernikov case NUD_PROBE: 28291fbe081SAlexander V. Chernikov lle_state = "P"; 28391fbe081SAlexander V. Chernikov break; 28491fbe081SAlexander V. Chernikov case NUD_FAILED: 28591fbe081SAlexander V. Chernikov lle_state = "F"; 28691fbe081SAlexander V. Chernikov break; 28791fbe081SAlexander V. Chernikov default: 28891fbe081SAlexander V. Chernikov lle_state = "N"; 28991fbe081SAlexander V. Chernikov break; 29091fbe081SAlexander V. Chernikov } 29191fbe081SAlexander V. Chernikov xo_emit(" {:neighbor-state/%s}", lle_state); 29291fbe081SAlexander V. Chernikov 29391fbe081SAlexander V. Chernikov bool isrouter = neigh->ndm_flags & NTF_ROUTER; 29491fbe081SAlexander V. Chernikov 29591fbe081SAlexander V. Chernikov /* 29691fbe081SAlexander V. Chernikov * other flags. R: router, P: proxy, W: ?? 29791fbe081SAlexander V. Chernikov */ 29891fbe081SAlexander V. Chernikov char flgbuf[8]; 29991fbe081SAlexander V. Chernikov snprintf(flgbuf, sizeof(flgbuf), "%s%s", 30091fbe081SAlexander V. Chernikov isrouter ? "R" : "", 30191fbe081SAlexander V. Chernikov (neigh->ndm_flags & NTF_PROXY) ? "p" : ""); 30291fbe081SAlexander V. Chernikov xo_emit(" {:nd-flags/%s}", flgbuf); 30391fbe081SAlexander V. Chernikov 30491fbe081SAlexander V. Chernikov if (neigh->nda_probes != 0) 30591fbe081SAlexander V. Chernikov xo_emit("{u:/ %d}", neigh->nda_probes); 30691fbe081SAlexander V. Chernikov 30791fbe081SAlexander V. Chernikov xo_emit("\n"); 30891fbe081SAlexander V. Chernikov xo_close_instance("neighbor-cache"); 30991fbe081SAlexander V. Chernikov } 31091fbe081SAlexander V. Chernikov 31191fbe081SAlexander V. Chernikov int 31291fbe081SAlexander V. Chernikov print_entries_nl(uint32_t ifindex, struct sockaddr_in6 *addr, bool cflag) 31391fbe081SAlexander V. Chernikov { 31491fbe081SAlexander V. Chernikov struct snl_state ss_req = {}, ss_cmd = {}; 31591fbe081SAlexander V. Chernikov struct snl_parsed_link_simple link = {}; 31691fbe081SAlexander V. Chernikov struct snl_writer nw; 317*b6d4e3beSZhenlei Huang struct nlmsghdr *hdr; 318*b6d4e3beSZhenlei Huang struct ndmsg *ndmsg; 31991fbe081SAlexander V. Chernikov 32091fbe081SAlexander V. Chernikov nl_init_socket(&ss_req); 32191fbe081SAlexander V. Chernikov snl_init_writer(&ss_req, &nw); 32291fbe081SAlexander V. Chernikov 323*b6d4e3beSZhenlei Huang /* Print header */ 324*b6d4e3beSZhenlei Huang if (!opts.tflag && !cflag) { 325*b6d4e3beSZhenlei Huang char xobuf[200]; 326*b6d4e3beSZhenlei Huang snprintf(xobuf, sizeof(xobuf), 327*b6d4e3beSZhenlei Huang "{T:/%%-%d.%ds} {T:/%%-%d.%ds} {T:/%%%d.%ds} {T:/%%-9.9s} {T:/%%1s} {T:/%%5s}\n", 328*b6d4e3beSZhenlei Huang W_ADDR, W_ADDR, W_LL, W_LL, W_IF, W_IF); 329*b6d4e3beSZhenlei Huang xo_emit(xobuf, "Neighbor", "Linklayer Address", "Netif", "Expire", "S", "Flags"); 330*b6d4e3beSZhenlei Huang } 331*b6d4e3beSZhenlei Huang 332*b6d4e3beSZhenlei Huang again: 333*b6d4e3beSZhenlei Huang hdr = snl_create_msg_request(&nw, RTM_GETNEIGH); 334*b6d4e3beSZhenlei Huang ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 33591fbe081SAlexander V. Chernikov if (ndmsg != NULL) { 33691fbe081SAlexander V. Chernikov ndmsg->ndm_family = AF_INET6; 33791fbe081SAlexander V. Chernikov ndmsg->ndm_ifindex = ifindex; 33891fbe081SAlexander V. Chernikov } 33991fbe081SAlexander V. Chernikov 3404f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(&ss_req, hdr)) { 34191fbe081SAlexander V. Chernikov snl_free(&ss_req); 34291fbe081SAlexander V. Chernikov return (0); 34391fbe081SAlexander V. Chernikov } 34491fbe081SAlexander V. Chernikov 34591fbe081SAlexander V. Chernikov uint32_t nlmsg_seq = hdr->nlmsg_seq; 34691fbe081SAlexander V. Chernikov struct snl_errmsg_data e = {}; 34791fbe081SAlexander V. Chernikov int count = 0; 34891fbe081SAlexander V. Chernikov nl_init_socket(&ss_cmd); 34991fbe081SAlexander V. Chernikov 35091fbe081SAlexander V. Chernikov xo_open_list("neighbor-cache"); 35191fbe081SAlexander V. Chernikov 35291fbe081SAlexander V. Chernikov while ((hdr = snl_read_reply_multi(&ss_req, nlmsg_seq, &e)) != NULL) { 35391fbe081SAlexander V. Chernikov struct snl_parsed_neigh neigh = {}; 35491fbe081SAlexander V. Chernikov 35591fbe081SAlexander V. Chernikov if (!snl_parse_nlmsg(&ss_req, hdr, &snl_rtm_neigh_parser, &neigh)) 35691fbe081SAlexander V. Chernikov continue; 35791fbe081SAlexander V. Chernikov 35891fbe081SAlexander V. Chernikov if (neigh.nda_ifindex != link.ifi_index) { 35991fbe081SAlexander V. Chernikov snl_clear_lb(&ss_cmd); 36091fbe081SAlexander V. Chernikov memset(&link, 0, sizeof(link)); 36191fbe081SAlexander V. Chernikov if (!get_link_info(&ss_cmd, neigh.nda_ifindex, &link)) 36291fbe081SAlexander V. Chernikov continue; 36391fbe081SAlexander V. Chernikov } 36491fbe081SAlexander V. Chernikov 36591fbe081SAlexander V. Chernikov /* TODO: embed LL in the parser */ 36691fbe081SAlexander V. Chernikov struct sockaddr_in6 *dst = (struct sockaddr_in6 *)neigh.nda_dst; 36791fbe081SAlexander V. Chernikov if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr)) 36891fbe081SAlexander V. Chernikov dst->sin6_scope_id = neigh.nda_ifindex; 36991fbe081SAlexander V. Chernikov 37091fbe081SAlexander V. Chernikov if (addr != NULL) { 37191fbe081SAlexander V. Chernikov if (IN6_ARE_ADDR_EQUAL(&addr->sin6_addr, 37291fbe081SAlexander V. Chernikov &dst->sin6_addr) == 0 || 37391fbe081SAlexander V. Chernikov addr->sin6_scope_id != dst->sin6_scope_id) 37491fbe081SAlexander V. Chernikov continue; 37591fbe081SAlexander V. Chernikov } 37691fbe081SAlexander V. Chernikov 37791fbe081SAlexander V. Chernikov if (cflag) { 37891fbe081SAlexander V. Chernikov char dst_str[INET6_ADDRSTRLEN]; 37991fbe081SAlexander V. Chernikov 38091fbe081SAlexander V. Chernikov inet_ntop(AF_INET6, &dst->sin6_addr, dst_str, sizeof(dst_str)); 381934a24e5SR. Christian McDonald delete_nl(neigh.nda_ifindex, dst_str, false); /* no warn */ 382934a24e5SR. Christian McDonald } else 383934a24e5SR. Christian McDonald print_entry(&neigh, &link); 384934a24e5SR. Christian McDonald 38591fbe081SAlexander V. Chernikov count++; 38691fbe081SAlexander V. Chernikov snl_clear_lb(&ss_req); 38791fbe081SAlexander V. Chernikov } 388*b6d4e3beSZhenlei Huang if (opts.repeat) { 389*b6d4e3beSZhenlei Huang xo_emit("\n"); 390*b6d4e3beSZhenlei Huang xo_flush(); 391*b6d4e3beSZhenlei Huang sleep(opts.repeat); 392*b6d4e3beSZhenlei Huang goto again; 393*b6d4e3beSZhenlei Huang } 39491fbe081SAlexander V. Chernikov xo_close_list("neighbor-cache"); 39591fbe081SAlexander V. Chernikov 39691fbe081SAlexander V. Chernikov snl_free(&ss_req); 39791fbe081SAlexander V. Chernikov snl_free(&ss_cmd); 39891fbe081SAlexander V. Chernikov 39991fbe081SAlexander V. Chernikov return (count); 40091fbe081SAlexander V. Chernikov } 40191fbe081SAlexander V. Chernikov 40291fbe081SAlexander V. Chernikov int 403934a24e5SR. Christian McDonald delete_nl(uint32_t ifindex, char *host, bool warn) 40491fbe081SAlexander V. Chernikov { 405934a24e5SR. Christian McDonald #define xo_warnx(...) do { if (warn) { xo_warnx(__VA_ARGS__); } } while(0) 40691fbe081SAlexander V. Chernikov struct snl_state ss = {}; 40791fbe081SAlexander V. Chernikov struct snl_writer nw; 40891fbe081SAlexander V. Chernikov struct sockaddr_in6 dst; 40991fbe081SAlexander V. Chernikov 41091fbe081SAlexander V. Chernikov int gai_error = getaddr(host, &dst); 41191fbe081SAlexander V. Chernikov if (gai_error) { 41291fbe081SAlexander V. Chernikov xo_warnx("%s: %s", host, gai_strerror(gai_error)); 41391fbe081SAlexander V. Chernikov return 1; 41491fbe081SAlexander V. Chernikov } 41591fbe081SAlexander V. Chernikov 41691fbe081SAlexander V. Chernikov nl_init_socket(&ss); 41791fbe081SAlexander V. Chernikov 41891fbe081SAlexander V. Chernikov ifindex = fix_ifindex(&ss, ifindex, &dst); 41991fbe081SAlexander V. Chernikov if (ifindex == 0) { 42091fbe081SAlexander V. Chernikov xo_warnx("delete: cannot locate %s", host); 42191fbe081SAlexander V. Chernikov snl_free(&ss); 42291fbe081SAlexander V. Chernikov return (0); 42391fbe081SAlexander V. Chernikov } 42491fbe081SAlexander V. Chernikov 42591fbe081SAlexander V. Chernikov snl_init_writer(&ss, &nw); 42691fbe081SAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_DELNEIGH); 42791fbe081SAlexander V. Chernikov struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 42891fbe081SAlexander V. Chernikov if (ndmsg != NULL) { 42991fbe081SAlexander V. Chernikov ndmsg->ndm_family = AF_INET6; 43091fbe081SAlexander V. Chernikov ndmsg->ndm_ifindex = ifindex; 43191fbe081SAlexander V. Chernikov } 43291fbe081SAlexander V. Chernikov snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)&dst); 43391fbe081SAlexander V. Chernikov 4344f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(&ss, hdr)) { 43591fbe081SAlexander V. Chernikov snl_free(&ss); 43691fbe081SAlexander V. Chernikov return (1); 43791fbe081SAlexander V. Chernikov } 43891fbe081SAlexander V. Chernikov 43991fbe081SAlexander V. Chernikov struct snl_errmsg_data e = {}; 44091fbe081SAlexander V. Chernikov snl_read_reply_code(&ss, hdr->nlmsg_seq, &e); 44191fbe081SAlexander V. Chernikov if (e.error != 0) { 44291fbe081SAlexander V. Chernikov if (e.error_str != NULL) 44391fbe081SAlexander V. Chernikov xo_warnx("delete %s: %s (%s)", host, strerror(e.error), e.error_str); 44491fbe081SAlexander V. Chernikov else 44591fbe081SAlexander V. Chernikov xo_warnx("delete %s: %s", host, strerror(e.error)); 44691fbe081SAlexander V. Chernikov } else { 44791fbe081SAlexander V. Chernikov char host_buf[NI_MAXHOST]; 44891fbe081SAlexander V. Chernikov char ifix_buf[IFNAMSIZ]; 44991fbe081SAlexander V. Chernikov 45091fbe081SAlexander V. Chernikov getnameinfo((struct sockaddr *)&dst, 45191fbe081SAlexander V. Chernikov dst.sin6_len, host_buf, 45291fbe081SAlexander V. Chernikov sizeof(host_buf), NULL, 0, 45391fbe081SAlexander V. Chernikov (opts.nflag ? NI_NUMERICHOST : 0)); 45491fbe081SAlexander V. Chernikov 45591fbe081SAlexander V. Chernikov char *ifname = if_indextoname(ifindex, ifix_buf); 45691fbe081SAlexander V. Chernikov if (ifname == NULL) { 45791fbe081SAlexander V. Chernikov strlcpy(ifix_buf, "?", sizeof(ifix_buf)); 45891fbe081SAlexander V. Chernikov ifname = ifix_buf; 45991fbe081SAlexander V. Chernikov } 46091fbe081SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN]; 46191fbe081SAlexander V. Chernikov inet_ntop(AF_INET6, &dst.sin6_addr, abuf, sizeof(abuf)); 46291fbe081SAlexander V. Chernikov 46391fbe081SAlexander V. Chernikov xo_open_instance("neighbor-cache"); 46491fbe081SAlexander V. Chernikov xo_emit("{:hostname/%s}{d:/ (%s) deleted\n}", host, host_buf); 46591fbe081SAlexander V. Chernikov xo_emit("{e:address/%s}{e:interface/%s}", abuf, ifname); 46691fbe081SAlexander V. Chernikov xo_close_instance("neighbor-cache"); 46791fbe081SAlexander V. Chernikov } 46891fbe081SAlexander V. Chernikov snl_free(&ss); 46991fbe081SAlexander V. Chernikov 47091fbe081SAlexander V. Chernikov return (e.error != 0); 471934a24e5SR. Christian McDonald #undef xo_warnx /* see above */ 47291fbe081SAlexander V. Chernikov } 47391fbe081SAlexander V. Chernikov 47491fbe081SAlexander V. Chernikov int 47591fbe081SAlexander V. Chernikov set_nl(uint32_t ifindex, struct sockaddr_in6 *dst, struct sockaddr_dl *sdl, char *host) 47691fbe081SAlexander V. Chernikov { 47791fbe081SAlexander V. Chernikov struct snl_state ss = {}; 47891fbe081SAlexander V. Chernikov struct snl_writer nw; 47991fbe081SAlexander V. Chernikov 48091fbe081SAlexander V. Chernikov nl_init_socket(&ss); 48191fbe081SAlexander V. Chernikov 48291fbe081SAlexander V. Chernikov ifindex = fix_ifindex(&ss, ifindex, dst); 48391fbe081SAlexander V. Chernikov if (ifindex == 0) { 48491fbe081SAlexander V. Chernikov xo_warnx("delete: cannot locate %s", host); 48591fbe081SAlexander V. Chernikov snl_free(&ss); 48691fbe081SAlexander V. Chernikov return (0); 48791fbe081SAlexander V. Chernikov } 48891fbe081SAlexander V. Chernikov 48991fbe081SAlexander V. Chernikov snl_init_writer(&ss, &nw); 49091fbe081SAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_NEWNEIGH); 49191fbe081SAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; 49291fbe081SAlexander V. Chernikov struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 49391fbe081SAlexander V. Chernikov if (ndmsg != NULL) { 49491fbe081SAlexander V. Chernikov uint8_t nl_flags = NTF_STICKY; 49591fbe081SAlexander V. Chernikov 49691fbe081SAlexander V. Chernikov ndmsg->ndm_family = AF_INET6; 49791fbe081SAlexander V. Chernikov ndmsg->ndm_ifindex = ifindex; 49891fbe081SAlexander V. Chernikov ndmsg->ndm_state = NUD_PERMANENT; 49991fbe081SAlexander V. Chernikov 50091fbe081SAlexander V. Chernikov if (opts.flags & RTF_ANNOUNCE) 50191fbe081SAlexander V. Chernikov nl_flags |= NTF_PROXY; 50291fbe081SAlexander V. Chernikov ndmsg->ndm_flags = nl_flags; 50391fbe081SAlexander V. Chernikov } 50491fbe081SAlexander V. Chernikov snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)dst); 50591fbe081SAlexander V. Chernikov snl_add_msg_attr(&nw, NDA_LLADDR, sdl->sdl_alen, LLADDR(sdl)); 50691fbe081SAlexander V. Chernikov 5074f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(&ss, hdr)) { 50891fbe081SAlexander V. Chernikov snl_free(&ss); 50991fbe081SAlexander V. Chernikov return (1); 51091fbe081SAlexander V. Chernikov } 51191fbe081SAlexander V. Chernikov 51291fbe081SAlexander V. Chernikov struct snl_errmsg_data e = {}; 51391fbe081SAlexander V. Chernikov snl_read_reply_code(&ss, hdr->nlmsg_seq, &e); 51491fbe081SAlexander V. Chernikov if (e.error != 0) { 51591fbe081SAlexander V. Chernikov if (e.error_str != NULL) 51691fbe081SAlexander V. Chernikov xo_warnx("set: %s: %s (%s)", host, strerror(e.error), e.error_str); 51791fbe081SAlexander V. Chernikov else 51891fbe081SAlexander V. Chernikov xo_warnx("set %s: %s", host, strerror(e.error)); 51991fbe081SAlexander V. Chernikov } 52091fbe081SAlexander V. Chernikov snl_free(&ss); 52191fbe081SAlexander V. Chernikov 52291fbe081SAlexander V. Chernikov return (e.error != 0); 52391fbe081SAlexander V. Chernikov } 52491fbe081SAlexander V. Chernikov 525