xref: /freebsd-src/usr.sbin/arp/arp_netlink.c (revision 417842f908619336dd4c739a92c326ade2c35770)
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