16ad73dbfSAlexander V. Chernikov #include <stdio.h> 26ad73dbfSAlexander V. Chernikov #include <stdlib.h> 36ad73dbfSAlexander V. Chernikov #include <string.h> 46ad73dbfSAlexander V. Chernikov #include <stdbool.h> 56ad73dbfSAlexander V. Chernikov #include <errno.h> 66ad73dbfSAlexander V. Chernikov #include <netdb.h> 76ad73dbfSAlexander V. Chernikov 86ad73dbfSAlexander V. Chernikov #include <sys/bitcount.h> 96ad73dbfSAlexander V. Chernikov #include <sys/param.h> 106ad73dbfSAlexander V. Chernikov #include <sys/linker.h> 116ad73dbfSAlexander V. Chernikov #include <sys/module.h> 126ad73dbfSAlexander V. Chernikov #include <sys/socket.h> 136ad73dbfSAlexander V. Chernikov #include <sys/sysctl.h> 146ad73dbfSAlexander V. Chernikov #include <sys/time.h> 156ad73dbfSAlexander V. Chernikov #include <sys/types.h> 166ad73dbfSAlexander V. Chernikov 176ad73dbfSAlexander V. Chernikov #include <netinet/in.h> 186ad73dbfSAlexander V. Chernikov #include <arpa/inet.h> 196ad73dbfSAlexander V. Chernikov 206ad73dbfSAlexander V. Chernikov #include <net/ethernet.h> 216ad73dbfSAlexander V. Chernikov #include <net/if.h> 226ad73dbfSAlexander V. Chernikov #include <net/if_dl.h> 236ad73dbfSAlexander V. Chernikov #include <net/if_types.h> 246ad73dbfSAlexander V. Chernikov #include <netlink/netlink.h> 256ad73dbfSAlexander V. Chernikov #include <netlink/netlink_route.h> 266ad73dbfSAlexander V. Chernikov #include <netlink/netlink_snl.h> 276ad73dbfSAlexander V. Chernikov #include <netlink/netlink_snl_route.h> 286ad73dbfSAlexander V. Chernikov #include <netlink/netlink_snl_route_compat.h> 296ad73dbfSAlexander V. Chernikov #include <netlink/netlink_snl_route_parsers.h> 306ad73dbfSAlexander V. Chernikov 316ad73dbfSAlexander V. Chernikov #include <libxo/xo.h> 326ad73dbfSAlexander V. Chernikov #include "arp.h" 336ad73dbfSAlexander V. Chernikov 346ad73dbfSAlexander V. Chernikov #define RTF_ANNOUNCE RTF_PROTO2 356ad73dbfSAlexander V. Chernikov 366ad73dbfSAlexander V. Chernikov static void 376ad73dbfSAlexander V. Chernikov nl_init_socket(struct snl_state *ss) 386ad73dbfSAlexander V. Chernikov { 396ad73dbfSAlexander V. Chernikov if (snl_init(ss, NETLINK_ROUTE)) 406ad73dbfSAlexander V. Chernikov return; 416ad73dbfSAlexander V. Chernikov 426ad73dbfSAlexander V. Chernikov if (modfind("netlink") == -1 && errno == ENOENT) { 436ad73dbfSAlexander V. Chernikov /* Try to load */ 446ad73dbfSAlexander V. Chernikov if (kldload("netlink") == -1) 45*417842f9SYan-Hao Wang xo_err(1, "netlink is not loaded and load attempt failed"); 466ad73dbfSAlexander V. Chernikov if (snl_init(ss, NETLINK_ROUTE)) 476ad73dbfSAlexander V. Chernikov return; 486ad73dbfSAlexander V. Chernikov } 496ad73dbfSAlexander V. Chernikov 50*417842f9SYan-Hao Wang xo_err(1, "unable to open netlink socket"); 516ad73dbfSAlexander V. Chernikov } 526ad73dbfSAlexander V. Chernikov 536ad73dbfSAlexander V. Chernikov static bool 546ad73dbfSAlexander V. Chernikov get_link_info(struct snl_state *ss, uint32_t ifindex, 556ad73dbfSAlexander V. Chernikov struct snl_parsed_link_simple *link) 566ad73dbfSAlexander V. Chernikov { 576ad73dbfSAlexander V. Chernikov struct snl_writer nw; 586ad73dbfSAlexander V. Chernikov 596ad73dbfSAlexander V. Chernikov snl_init_writer(ss, &nw); 606ad73dbfSAlexander V. Chernikov 616ad73dbfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 626ad73dbfSAlexander V. Chernikov struct ifinfomsg *ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg); 636ad73dbfSAlexander V. Chernikov if (ifmsg != NULL) 646ad73dbfSAlexander V. Chernikov ifmsg->ifi_index = ifindex; 654f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 666ad73dbfSAlexander V. Chernikov return (false); 676ad73dbfSAlexander V. Chernikov 686ad73dbfSAlexander V. Chernikov hdr = snl_read_reply(ss, hdr->nlmsg_seq); 696ad73dbfSAlexander V. Chernikov 706ad73dbfSAlexander V. Chernikov if (hdr == NULL || hdr->nlmsg_type != RTM_NEWLINK) 716ad73dbfSAlexander V. Chernikov return (false); 726ad73dbfSAlexander V. Chernikov 736ad73dbfSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, link)) 746ad73dbfSAlexander V. Chernikov return (false); 756ad73dbfSAlexander V. Chernikov 766ad73dbfSAlexander V. Chernikov return (true); 776ad73dbfSAlexander V. Chernikov } 786ad73dbfSAlexander V. Chernikov 796ad73dbfSAlexander V. Chernikov 806ad73dbfSAlexander V. Chernikov 816ad73dbfSAlexander V. Chernikov static bool 826ad73dbfSAlexander V. Chernikov has_l2(struct snl_state *ss, uint32_t ifindex) 836ad73dbfSAlexander V. Chernikov { 846ad73dbfSAlexander V. Chernikov struct snl_parsed_link_simple link = {}; 856ad73dbfSAlexander V. Chernikov 866ad73dbfSAlexander V. Chernikov if (!get_link_info(ss, ifindex, &link)) 876ad73dbfSAlexander V. Chernikov return (false); 886ad73dbfSAlexander V. Chernikov 896ad73dbfSAlexander V. Chernikov return (valid_type(link.ifi_type) != 0); 906ad73dbfSAlexander V. Chernikov } 916ad73dbfSAlexander V. Chernikov 926ad73dbfSAlexander V. Chernikov static uint32_t 932d7842d0SJohn Baldwin get_myfib(void) 946ad73dbfSAlexander V. Chernikov { 956ad73dbfSAlexander V. Chernikov uint32_t fibnum = 0; 966ad73dbfSAlexander V. Chernikov size_t len = sizeof(fibnum); 976ad73dbfSAlexander V. Chernikov 986ad73dbfSAlexander V. Chernikov sysctlbyname("net.my_fibnum", (void *)&fibnum, &len, NULL, 0); 996ad73dbfSAlexander V. Chernikov 1006ad73dbfSAlexander V. Chernikov return (fibnum); 1016ad73dbfSAlexander V. Chernikov } 1026ad73dbfSAlexander V. Chernikov 1036ad73dbfSAlexander V. Chernikov static int 1046ad73dbfSAlexander V. Chernikov guess_ifindex(struct snl_state *ss, uint32_t fibnum, struct in_addr addr) 1056ad73dbfSAlexander V. Chernikov { 1066ad73dbfSAlexander V. Chernikov struct snl_writer nw; 1076ad73dbfSAlexander V. Chernikov 1086ad73dbfSAlexander V. Chernikov snl_init_writer(ss, &nw); 1096ad73dbfSAlexander V. Chernikov 1106ad73dbfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETROUTE); 1116ad73dbfSAlexander V. Chernikov struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg); 1126ad73dbfSAlexander V. Chernikov rtm->rtm_family = AF_INET; 1136ad73dbfSAlexander V. Chernikov 1146ad73dbfSAlexander V. Chernikov struct sockaddr_in dst = { .sin_family = AF_INET, .sin_addr = addr }; 1156ad73dbfSAlexander V. Chernikov snl_add_msg_attr_ip(&nw, RTA_DST, (struct sockaddr *)&dst); 1166ad73dbfSAlexander V. Chernikov snl_add_msg_attr_u32(&nw, RTA_TABLE, fibnum); 1176ad73dbfSAlexander V. Chernikov 1184f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 1196ad73dbfSAlexander V. Chernikov return (0); 1206ad73dbfSAlexander V. Chernikov 1216ad73dbfSAlexander V. Chernikov hdr = snl_read_reply(ss, hdr->nlmsg_seq); 1226ad73dbfSAlexander V. Chernikov 1236ad73dbfSAlexander V. Chernikov if (hdr->nlmsg_type != NL_RTM_NEWROUTE) { 1246ad73dbfSAlexander V. Chernikov /* No route found, unable to guess ifindex */ 1256ad73dbfSAlexander V. Chernikov return (0); 1266ad73dbfSAlexander V. Chernikov } 1276ad73dbfSAlexander V. Chernikov 1286ad73dbfSAlexander V. Chernikov struct snl_parsed_route r = {}; 1296ad73dbfSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r)) 1306ad73dbfSAlexander V. Chernikov return (0); 1316ad73dbfSAlexander V. Chernikov 132c9090124SAlexander V. Chernikov if (r.rta_multipath.num_nhops > 0 || (r.rta_rtflags & RTF_GATEWAY)) 1336ad73dbfSAlexander V. Chernikov return (0); 1346ad73dbfSAlexander V. Chernikov 1356ad73dbfSAlexander V. Chernikov /* Check if the interface is of supported type */ 1366ad73dbfSAlexander V. Chernikov if (has_l2(ss, r.rta_oif)) 1376ad73dbfSAlexander V. Chernikov return (r.rta_oif); 1386ad73dbfSAlexander V. Chernikov 1396ad73dbfSAlexander V. Chernikov /* Check the case when we matched the loopback route for P2P */ 1406ad73dbfSAlexander V. Chernikov snl_init_writer(ss, &nw); 1416ad73dbfSAlexander V. Chernikov hdr = snl_create_msg_request(&nw, RTM_GETNEXTHOP); 1426ad73dbfSAlexander V. Chernikov snl_reserve_msg_object(&nw, struct nhmsg); 1436ad73dbfSAlexander V. Chernikov 1446ad73dbfSAlexander V. Chernikov int off = snl_add_msg_attr_nested(&nw, NHA_FREEBSD); 1456ad73dbfSAlexander V. Chernikov snl_add_msg_attr_u32(&nw, NHAF_KID, r.rta_knh_id); 1466ad73dbfSAlexander V. Chernikov snl_add_msg_attr_u8(&nw, NHAF_FAMILY, AF_INET); 1476ad73dbfSAlexander V. Chernikov snl_add_msg_attr_u32(&nw, NHAF_TABLE, fibnum); 1486ad73dbfSAlexander V. Chernikov snl_end_attr_nested(&nw, off); 1496ad73dbfSAlexander V. Chernikov 1504f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 1516ad73dbfSAlexander V. Chernikov return (0); 1526ad73dbfSAlexander V. Chernikov 1536ad73dbfSAlexander V. Chernikov hdr = snl_read_reply(ss, hdr->nlmsg_seq); 1546ad73dbfSAlexander V. Chernikov 1556ad73dbfSAlexander V. Chernikov if (hdr->nlmsg_type != NL_RTM_NEWNEXTHOP) { 1566ad73dbfSAlexander V. Chernikov /* No nexthop found, unable to guess ifindex */ 1576ad73dbfSAlexander V. Chernikov return (0); 1586ad73dbfSAlexander V. Chernikov } 1596ad73dbfSAlexander V. Chernikov 1606ad73dbfSAlexander V. Chernikov struct snl_parsed_nhop nh = {}; 1616ad73dbfSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_nhmsg_parser, &nh)) 1626ad73dbfSAlexander V. Chernikov return (0); 1636ad73dbfSAlexander V. Chernikov 1646ad73dbfSAlexander V. Chernikov return (nh.nhaf_aif); 1656ad73dbfSAlexander V. Chernikov } 1666ad73dbfSAlexander V. Chernikov 1676ad73dbfSAlexander V. Chernikov static uint32_t 1686ad73dbfSAlexander V. Chernikov fix_ifindex(struct snl_state *ss, uint32_t ifindex, struct in_addr addr) 1696ad73dbfSAlexander V. Chernikov { 1706ad73dbfSAlexander V. Chernikov if (ifindex == 0) 1716ad73dbfSAlexander V. Chernikov ifindex = guess_ifindex(ss, get_myfib(), addr); 1726ad73dbfSAlexander V. Chernikov return (ifindex); 1736ad73dbfSAlexander V. Chernikov } 1746ad73dbfSAlexander V. Chernikov 1756ad73dbfSAlexander V. Chernikov static void 1766ad73dbfSAlexander V. Chernikov print_entry(struct snl_parsed_neigh *neigh, struct snl_parsed_link_simple *link) 1776ad73dbfSAlexander V. Chernikov { 1786ad73dbfSAlexander V. Chernikov const char *host; 1796ad73dbfSAlexander V. Chernikov struct hostent *hp; 1806ad73dbfSAlexander V. Chernikov struct sockaddr_in *addr = (struct sockaddr_in *)neigh->nda_dst; 1816ad73dbfSAlexander V. Chernikov 1826ad73dbfSAlexander V. Chernikov xo_open_instance("arp-cache"); 1836ad73dbfSAlexander V. Chernikov 1846ad73dbfSAlexander V. Chernikov if (!opts.nflag) 1856ad73dbfSAlexander V. Chernikov hp = gethostbyaddr((caddr_t)&(addr->sin_addr), 1866ad73dbfSAlexander V. Chernikov sizeof(addr->sin_addr), AF_INET); 1876ad73dbfSAlexander V. Chernikov else 1886ad73dbfSAlexander V. Chernikov hp = 0; 1896ad73dbfSAlexander V. Chernikov if (hp) 1906ad73dbfSAlexander V. Chernikov host = hp->h_name; 1916ad73dbfSAlexander V. Chernikov else { 1926ad73dbfSAlexander V. Chernikov host = "?"; 1936ad73dbfSAlexander V. Chernikov if (h_errno == TRY_AGAIN) 1946ad73dbfSAlexander V. Chernikov opts.nflag = true; 1956ad73dbfSAlexander V. Chernikov } 1966ad73dbfSAlexander V. Chernikov xo_emit("{:hostname/%s} ({:ip-address/%s}) at ", host, 1976ad73dbfSAlexander V. Chernikov inet_ntoa(addr->sin_addr)); 1986ad73dbfSAlexander V. Chernikov if (neigh->nda_lladdr != NULL) { 1996ad73dbfSAlexander V. Chernikov struct sockaddr_dl sdl = { 2006ad73dbfSAlexander V. Chernikov .sdl_family = AF_LINK, 2016ad73dbfSAlexander V. Chernikov .sdl_type = link->ifi_type, 2026ad73dbfSAlexander V. Chernikov .sdl_len = sizeof(struct sockaddr_dl), 2036ad73dbfSAlexander V. Chernikov .sdl_alen = NLA_DATA_LEN(neigh->nda_lladdr), 2046ad73dbfSAlexander V. Chernikov }; 2056ad73dbfSAlexander V. Chernikov memcpy(sdl.sdl_data, NLA_DATA(neigh->nda_lladdr), sdl.sdl_alen); 2066ad73dbfSAlexander V. Chernikov 2076ad73dbfSAlexander V. Chernikov if ((sdl.sdl_type == IFT_ETHER || 2086ad73dbfSAlexander V. Chernikov sdl.sdl_type == IFT_L2VLAN || 2096ad73dbfSAlexander V. Chernikov sdl.sdl_type == IFT_BRIDGE) && 2106ad73dbfSAlexander V. Chernikov sdl.sdl_alen == ETHER_ADDR_LEN) 2116ad73dbfSAlexander V. Chernikov xo_emit("{:mac-address/%s}", 2126ad73dbfSAlexander V. Chernikov ether_ntoa((struct ether_addr *)LLADDR(&sdl))); 2136ad73dbfSAlexander V. Chernikov else { 2146ad73dbfSAlexander V. Chernikov 2156ad73dbfSAlexander V. Chernikov xo_emit("{:mac-address/%s}", link_ntoa(&sdl)); 2166ad73dbfSAlexander V. Chernikov } 2176ad73dbfSAlexander V. Chernikov } else 2186ad73dbfSAlexander V. Chernikov xo_emit("{d:/(incomplete)}{en:incomplete/true}"); 2196ad73dbfSAlexander V. Chernikov xo_emit(" on {:interface/%s}", link->ifla_ifname); 2206ad73dbfSAlexander V. Chernikov 2216ad73dbfSAlexander V. Chernikov if (neigh->ndaf_next_ts == 0) 2226ad73dbfSAlexander V. Chernikov xo_emit("{d:/ permanent}{en:permanent/true}"); 2236ad73dbfSAlexander V. Chernikov else { 2246ad73dbfSAlexander V. Chernikov time_t expire_time; 2256ad73dbfSAlexander V. Chernikov struct timeval now; 2266ad73dbfSAlexander V. Chernikov 2276ad73dbfSAlexander V. Chernikov gettimeofday(&now, 0); 2286ad73dbfSAlexander V. Chernikov if ((expire_time = neigh->ndaf_next_ts - now.tv_sec) > 0) 2296ad73dbfSAlexander V. Chernikov xo_emit(" expires in {:expires/%d} seconds", 2306ad73dbfSAlexander V. Chernikov (int)expire_time); 2316ad73dbfSAlexander V. Chernikov else 2326ad73dbfSAlexander V. Chernikov xo_emit("{d:/ expired}{en:expired/true}"); 2336ad73dbfSAlexander V. Chernikov } 2346ad73dbfSAlexander V. Chernikov 2356ad73dbfSAlexander V. Chernikov if (neigh->ndm_flags & NTF_PROXY) 2366ad73dbfSAlexander V. Chernikov xo_emit("{d:/ published}{en:published/true}"); 2376ad73dbfSAlexander V. Chernikov 2386ad73dbfSAlexander V. Chernikov switch(link->ifi_type) { 2396ad73dbfSAlexander V. Chernikov case IFT_ETHER: 2406ad73dbfSAlexander V. Chernikov xo_emit(" [{:type/ethernet}]"); 2416ad73dbfSAlexander V. Chernikov break; 2426ad73dbfSAlexander V. Chernikov case IFT_FDDI: 2436ad73dbfSAlexander V. Chernikov xo_emit(" [{:type/fddi}]"); 2446ad73dbfSAlexander V. Chernikov break; 2456ad73dbfSAlexander V. Chernikov case IFT_ATM: 2466ad73dbfSAlexander V. Chernikov xo_emit(" [{:type/atm}]"); 2476ad73dbfSAlexander V. Chernikov break; 2486ad73dbfSAlexander V. Chernikov case IFT_L2VLAN: 2496ad73dbfSAlexander V. Chernikov xo_emit(" [{:type/vlan}]"); 2506ad73dbfSAlexander V. Chernikov break; 2516ad73dbfSAlexander V. Chernikov case IFT_IEEE1394: 2526ad73dbfSAlexander V. Chernikov xo_emit(" [{:type/firewire}]"); 2536ad73dbfSAlexander V. Chernikov break; 2546ad73dbfSAlexander V. Chernikov case IFT_BRIDGE: 2556ad73dbfSAlexander V. Chernikov xo_emit(" [{:type/bridge}]"); 2566ad73dbfSAlexander V. Chernikov break; 2576ad73dbfSAlexander V. Chernikov case IFT_INFINIBAND: 2586ad73dbfSAlexander V. Chernikov xo_emit(" [{:type/infiniband}]"); 2596ad73dbfSAlexander V. Chernikov break; 2606ad73dbfSAlexander V. Chernikov default: 2616ad73dbfSAlexander V. Chernikov break; 2626ad73dbfSAlexander V. Chernikov } 2636ad73dbfSAlexander V. Chernikov 2646ad73dbfSAlexander V. Chernikov xo_emit("\n"); 2656ad73dbfSAlexander V. Chernikov 2666ad73dbfSAlexander V. Chernikov xo_close_instance("arp-cache"); 2676ad73dbfSAlexander V. Chernikov } 2686ad73dbfSAlexander V. Chernikov 2696ad73dbfSAlexander V. Chernikov int 2706ad73dbfSAlexander V. Chernikov print_entries_nl(uint32_t ifindex, struct in_addr addr) 2716ad73dbfSAlexander V. Chernikov { 2726ad73dbfSAlexander V. Chernikov struct snl_state ss_req = {}, ss_cmd = {}; 2736ad73dbfSAlexander V. Chernikov struct snl_parsed_link_simple link = {}; 2746ad73dbfSAlexander V. Chernikov struct snl_writer nw; 2756ad73dbfSAlexander V. Chernikov 2766ad73dbfSAlexander V. Chernikov nl_init_socket(&ss_req); 2776ad73dbfSAlexander V. Chernikov snl_init_writer(&ss_req, &nw); 2786ad73dbfSAlexander V. Chernikov 2796ad73dbfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETNEIGH); 2806ad73dbfSAlexander V. Chernikov struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 2816ad73dbfSAlexander V. Chernikov if (ndmsg != NULL) { 2826ad73dbfSAlexander V. Chernikov ndmsg->ndm_family = AF_INET; 28379278872SR. Christian McDonald /* let kernel filter results by interface if provided */ 2846ad73dbfSAlexander V. Chernikov ndmsg->ndm_ifindex = ifindex; 2856ad73dbfSAlexander V. Chernikov } 2866ad73dbfSAlexander V. Chernikov 2874f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(&ss_req, hdr)) { 2886ad73dbfSAlexander V. Chernikov snl_free(&ss_req); 2896ad73dbfSAlexander V. Chernikov return (0); 2906ad73dbfSAlexander V. Chernikov } 2916ad73dbfSAlexander V. Chernikov 2926ad73dbfSAlexander V. Chernikov uint32_t nlmsg_seq = hdr->nlmsg_seq; 2936ad73dbfSAlexander V. Chernikov struct snl_errmsg_data e = {}; 2946ad73dbfSAlexander V. Chernikov int count = 0; 2956ad73dbfSAlexander V. Chernikov nl_init_socket(&ss_cmd); 2966ad73dbfSAlexander V. Chernikov 2976ad73dbfSAlexander V. Chernikov while ((hdr = snl_read_reply_multi(&ss_req, nlmsg_seq, &e)) != NULL) { 2986ad73dbfSAlexander V. Chernikov struct snl_parsed_neigh neigh = {}; 29979278872SR. Christian McDonald struct sockaddr_in *neighaddr; 3006ad73dbfSAlexander V. Chernikov 3016ad73dbfSAlexander V. Chernikov if (!snl_parse_nlmsg(&ss_req, hdr, &snl_rtm_neigh_parser, &neigh)) 3026ad73dbfSAlexander V. Chernikov continue; 3036ad73dbfSAlexander V. Chernikov 3046ad73dbfSAlexander V. Chernikov if (neigh.nda_ifindex != link.ifi_index) { 3056ad73dbfSAlexander V. Chernikov snl_clear_lb(&ss_cmd); 3066ad73dbfSAlexander V. Chernikov memset(&link, 0, sizeof(link)); 3076ad73dbfSAlexander V. Chernikov if (!get_link_info(&ss_cmd, neigh.nda_ifindex, &link)) 3086ad73dbfSAlexander V. Chernikov continue; 3096ad73dbfSAlexander V. Chernikov } 3106ad73dbfSAlexander V. Chernikov 31179278872SR. Christian McDonald /* filter results based on host if provided */ 31279278872SR. Christian McDonald neighaddr = (struct sockaddr_in *)neigh.nda_dst; 31379278872SR. Christian McDonald if (addr.s_addr && 31479278872SR. Christian McDonald (addr.s_addr != neighaddr->sin_addr.s_addr)) 31579278872SR. Christian McDonald continue; 31679278872SR. Christian McDonald 3176ad73dbfSAlexander V. Chernikov print_entry(&neigh, &link); 3186ad73dbfSAlexander V. Chernikov count++; 3196ad73dbfSAlexander V. Chernikov snl_clear_lb(&ss_req); 3206ad73dbfSAlexander V. Chernikov } 3216ad73dbfSAlexander V. Chernikov 3226ad73dbfSAlexander V. Chernikov snl_free(&ss_req); 3236ad73dbfSAlexander V. Chernikov snl_free(&ss_cmd); 3246ad73dbfSAlexander V. Chernikov 3256ad73dbfSAlexander V. Chernikov return (count); 3266ad73dbfSAlexander V. Chernikov } 3276ad73dbfSAlexander V. Chernikov 3286ad73dbfSAlexander V. Chernikov int 3296ad73dbfSAlexander V. Chernikov delete_nl(uint32_t ifindex, char *host) 3306ad73dbfSAlexander V. Chernikov { 3316ad73dbfSAlexander V. Chernikov struct snl_state ss = {}; 3326ad73dbfSAlexander V. Chernikov struct snl_writer nw; 3336ad73dbfSAlexander V. Chernikov struct sockaddr_in *dst; 3346ad73dbfSAlexander V. Chernikov 3356ad73dbfSAlexander V. Chernikov dst = getaddr(host); 3366ad73dbfSAlexander V. Chernikov if (dst == NULL) 3376ad73dbfSAlexander V. Chernikov return (1); 3386ad73dbfSAlexander V. Chernikov 3396ad73dbfSAlexander V. Chernikov nl_init_socket(&ss); 3406ad73dbfSAlexander V. Chernikov 3416ad73dbfSAlexander V. Chernikov ifindex = fix_ifindex(&ss, ifindex, dst->sin_addr); 3426ad73dbfSAlexander V. Chernikov if (ifindex == 0) { 3436ad73dbfSAlexander V. Chernikov xo_warnx("delete: cannot locate %s", host); 3446ad73dbfSAlexander V. Chernikov snl_free(&ss); 3456ad73dbfSAlexander V. Chernikov return (0); 3466ad73dbfSAlexander V. Chernikov } 3476ad73dbfSAlexander V. Chernikov 3486ad73dbfSAlexander V. Chernikov snl_init_writer(&ss, &nw); 3496ad73dbfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_DELNEIGH); 3506ad73dbfSAlexander V. Chernikov struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 3516ad73dbfSAlexander V. Chernikov if (ndmsg != NULL) { 3526ad73dbfSAlexander V. Chernikov ndmsg->ndm_family = AF_INET; 3536ad73dbfSAlexander V. Chernikov ndmsg->ndm_ifindex = ifindex; 3546ad73dbfSAlexander V. Chernikov } 3556ad73dbfSAlexander V. Chernikov snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)dst); 3566ad73dbfSAlexander V. Chernikov 3574f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(&ss, hdr)) { 3586ad73dbfSAlexander V. Chernikov snl_free(&ss); 3596ad73dbfSAlexander V. Chernikov return (1); 3606ad73dbfSAlexander V. Chernikov } 3616ad73dbfSAlexander V. Chernikov 3626ad73dbfSAlexander V. Chernikov struct snl_errmsg_data e = {}; 3636ad73dbfSAlexander V. Chernikov snl_read_reply_code(&ss, hdr->nlmsg_seq, &e); 3646ad73dbfSAlexander V. Chernikov if (e.error != 0) { 3656ad73dbfSAlexander V. Chernikov if (e.error_str != NULL) 3666ad73dbfSAlexander V. Chernikov xo_warnx("delete %s: %s (%s)", host, strerror(e.error), e.error_str); 3676ad73dbfSAlexander V. Chernikov else 3686ad73dbfSAlexander V. Chernikov xo_warnx("delete %s: %s", host, strerror(e.error)); 36952199877SAlexander V. Chernikov } else 37052199877SAlexander V. Chernikov printf("%s (%s) deleted\n", host, inet_ntoa(dst->sin_addr)); 37152199877SAlexander V. Chernikov 3726ad73dbfSAlexander V. Chernikov snl_free(&ss); 3736ad73dbfSAlexander V. Chernikov 3746ad73dbfSAlexander V. Chernikov return (e.error != 0); 3756ad73dbfSAlexander V. Chernikov } 3766ad73dbfSAlexander V. Chernikov 3776ad73dbfSAlexander V. Chernikov int 3786ad73dbfSAlexander V. Chernikov set_nl(uint32_t ifindex, struct sockaddr_in *dst, struct sockaddr_dl *sdl, char *host) 3796ad73dbfSAlexander V. Chernikov { 3806ad73dbfSAlexander V. Chernikov struct snl_state ss = {}; 3816ad73dbfSAlexander V. Chernikov struct snl_writer nw; 3826ad73dbfSAlexander V. Chernikov 3836ad73dbfSAlexander V. Chernikov nl_init_socket(&ss); 3846ad73dbfSAlexander V. Chernikov 3856ad73dbfSAlexander V. Chernikov ifindex = fix_ifindex(&ss, ifindex, dst->sin_addr); 3866ad73dbfSAlexander V. Chernikov if (ifindex == 0) { 3870ad9b235SLexi Winter xo_warnx("set: cannot locate %s", host); 3886ad73dbfSAlexander V. Chernikov snl_free(&ss); 3896ad73dbfSAlexander V. Chernikov return (0); 3906ad73dbfSAlexander V. Chernikov } 3916ad73dbfSAlexander V. Chernikov 3926ad73dbfSAlexander V. Chernikov snl_init_writer(&ss, &nw); 3936ad73dbfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_NEWNEIGH); 3946ad73dbfSAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; 3956ad73dbfSAlexander V. Chernikov struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 3966ad73dbfSAlexander V. Chernikov if (ndmsg != NULL) { 3976ad73dbfSAlexander V. Chernikov uint8_t nl_flags = 0; 3986ad73dbfSAlexander V. Chernikov 3996ad73dbfSAlexander V. Chernikov ndmsg->ndm_family = AF_INET; 4006ad73dbfSAlexander V. Chernikov ndmsg->ndm_ifindex = ifindex; 4016a3e87e1SGleb Smirnoff ndmsg->ndm_state = (opts.expire_time == 0) ? \ 4026a3e87e1SGleb Smirnoff NUD_PERMANENT : NUD_NONE; 4036ad73dbfSAlexander V. Chernikov 4046ad73dbfSAlexander V. Chernikov if (opts.flags & RTF_ANNOUNCE) 4056ad73dbfSAlexander V. Chernikov nl_flags |= NTF_PROXY; 4066a3e87e1SGleb Smirnoff if (opts.expire_time == 0) 4076ad73dbfSAlexander V. Chernikov nl_flags |= NTF_STICKY; 4086ad73dbfSAlexander V. Chernikov ndmsg->ndm_flags = nl_flags; 4096ad73dbfSAlexander V. Chernikov } 4106ad73dbfSAlexander V. Chernikov snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)dst); 4116ad73dbfSAlexander V. Chernikov snl_add_msg_attr(&nw, NDA_LLADDR, sdl->sdl_alen, LLADDR(sdl)); 4126ad73dbfSAlexander V. Chernikov 4136ad73dbfSAlexander V. Chernikov if (opts.expire_time != 0) { 4146ad73dbfSAlexander V. Chernikov struct timeval now; 4156ad73dbfSAlexander V. Chernikov 4166ad73dbfSAlexander V. Chernikov gettimeofday(&now, 0); 4176ad73dbfSAlexander V. Chernikov int off = snl_add_msg_attr_nested(&nw, NDA_FREEBSD); 4186ad73dbfSAlexander V. Chernikov snl_add_msg_attr_u32(&nw, NDAF_NEXT_STATE_TS, now.tv_sec + opts.expire_time); 4196ad73dbfSAlexander V. Chernikov snl_end_attr_nested(&nw, off); 4206ad73dbfSAlexander V. Chernikov } 4216ad73dbfSAlexander V. Chernikov 4224f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(&ss, hdr)) { 4236ad73dbfSAlexander V. Chernikov snl_free(&ss); 4246ad73dbfSAlexander V. Chernikov return (1); 4256ad73dbfSAlexander V. Chernikov } 4266ad73dbfSAlexander V. Chernikov 4276ad73dbfSAlexander V. Chernikov struct snl_errmsg_data e = {}; 4286ad73dbfSAlexander V. Chernikov snl_read_reply_code(&ss, hdr->nlmsg_seq, &e); 4296ad73dbfSAlexander V. Chernikov if (e.error != 0) { 4306ad73dbfSAlexander V. Chernikov if (e.error_str != NULL) 4316ad73dbfSAlexander V. Chernikov xo_warnx("set: %s: %s (%s)", host, strerror(e.error), e.error_str); 4326ad73dbfSAlexander V. Chernikov else 4336ad73dbfSAlexander V. Chernikov xo_warnx("set %s: %s", host, strerror(e.error)); 4346ad73dbfSAlexander V. Chernikov } 4356ad73dbfSAlexander V. Chernikov snl_free(&ss); 4366ad73dbfSAlexander V. Chernikov 4376ad73dbfSAlexander V. Chernikov return (e.error != 0); 4386ad73dbfSAlexander V. Chernikov } 4396ad73dbfSAlexander V. Chernikov 440