Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F156702386
D39720.id120994.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
D39720.id120994.diff
View Options
diff --git a/usr.sbin/arp/Makefile b/usr.sbin/arp/Makefile
--- a/usr.sbin/arp/Makefile
+++ b/usr.sbin/arp/Makefile
@@ -1,9 +1,20 @@
# @(#)Makefile 8.2 (Berkeley) 4/18/94
# $FreeBSD$
+.include <src.opts.mk>
+
PROG= arp
MAN= arp.4 arp.8
+
+SRCS= arp.c
+
+.if ${MK_NETLINK_SUPPORT} != "no"
+SRCS+= arp_netlink.c
+.else
+CFLAGS+=-DWITHOUT_NETLINK
+.endif
+
LIBADD= xo
WARNS?= 3
diff --git a/usr.sbin/arp/arp.h b/usr.sbin/arp/arp.h
new file mode 100644
--- /dev/null
+++ b/usr.sbin/arp/arp.h
@@ -0,0 +1,21 @@
+#ifndef _USR_SBIN_ARP_ARP_H_
+#define _USR_SBIN_ARP_ARP_H_
+
+int valid_type(int type);
+struct sockaddr_in *getaddr(char *host);
+int print_entries_nl(uint32_t ifindex, struct in_addr addr);
+
+struct arp_opts {
+ bool aflag;
+ bool nflag;
+ time_t expire_time;
+ int flags;
+};
+extern struct arp_opts opts;
+
+int print_entries_nl(uint32_t ifindex, struct in_addr addr);
+int delete_nl(uint32_t ifindex, char *host);
+int set_nl(uint32_t ifindex, struct sockaddr_in *dst, struct sockaddr_dl *sdl,
+ char *host);
+
+#endif
diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c
--- a/usr.sbin/arp/arp.c
+++ b/usr.sbin/arp/arp.c
@@ -74,6 +74,7 @@
#include <netdb.h>
#include <nlist.h>
#include <paths.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -81,13 +82,12 @@
#include <unistd.h>
#include <ifaddrs.h>
#include <libxo/xo.h>
+#include "arp.h"
typedef void (action_fn)(struct sockaddr_dl *sdl, struct sockaddr_in *s_in,
struct rt_msghdr *rtm);
-
-static int search(u_long addr, action_fn *action);
-static action_fn print_entry;
-static action_fn nuke_entry;
+static void nuke_entries(uint32_t ifindex, struct in_addr addr);
+static int print_entries(uint32_t ifindex, struct in_addr addr);
static int delete(char *host);
static void usage(void);
@@ -97,17 +97,15 @@
static struct rt_msghdr *rtmsg(int cmd,
struct sockaddr_in *dst, struct sockaddr_dl *sdl);
static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr);
-static struct sockaddr_in *getaddr(char *host);
-static int valid_type(int type);
+static int set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m,
+ char *host);
-static int nflag; /* no reverse dns lookups */
static char *rifname;
-static time_t expire_time;
-static int flags, doing_proxy;
-
struct if_nameindex *ifnameindex;
+struct arp_opts opts = {};
+
/* which function we're supposed to do */
#define F_GET 1
#define F_SET 2
@@ -124,7 +122,6 @@
{
int ch, func = 0;
int rtn = 0;
- int aflag = 0; /* do it for all entries */
argc = xo_parse_args(argc, argv);
if (argc < 0)
@@ -133,13 +130,13 @@
while ((ch = getopt(argc, argv, "andfsSi:")) != -1)
switch(ch) {
case 'a':
- aflag = 1;
+ opts.aflag = true;
break;
case 'd':
SETFUNC(F_DELETE);
break;
case 'n':
- nflag = 1;
+ opts.nflag = true;
break;
case 'S':
SETFUNC(F_REPLACE);
@@ -163,7 +160,7 @@
if (!func)
func = F_GET;
if (rifname) {
- if (func != F_GET && !(func == F_DELETE && aflag))
+ if (func != F_GET && !(func == F_DELETE && opts.aflag))
xo_errx(1, "-i not applicable to this operation");
if (if_nametoindex(rifname) == 0) {
if (errno == ENXIO)
@@ -175,7 +172,7 @@
}
switch (func) {
case F_GET:
- if (aflag) {
+ if (opts.aflag) {
if (argc != 0)
usage();
@@ -183,7 +180,8 @@
xo_open_container("arp");
xo_open_list("arp-cache");
- search(0, print_entry);
+ struct in_addr all_addrs = {};
+ print_entries(0, all_addrs);
xo_close_list("arp-cache");
xo_close_container("arp");
@@ -203,10 +201,11 @@
rtn = set(argc, argv) ? 1 : 0;
break;
case F_DELETE:
- if (aflag) {
+ if (opts.aflag) {
if (argc != 0)
usage();
- search(0, nuke_entry);
+ struct in_addr all_addrs = {};
+ nuke_entries(0, all_addrs);
} else {
if (argc != 1)
usage();
@@ -269,7 +268,7 @@
* the address of the host and returns a pointer to the
* structure.
*/
-static struct sockaddr_in *
+struct sockaddr_in *
getaddr(char *host)
{
struct hostent *hp;
@@ -290,10 +289,11 @@
return (&reply);
}
+int valid_type(int type);
/*
* Returns true if the type is a valid one for ARP.
*/
-static int
+int
valid_type(int type)
{
@@ -318,10 +318,7 @@
static int
set(int argc, char **argv)
{
- struct sockaddr_in *addr;
struct sockaddr_in *dst; /* what are we looking for */
- struct sockaddr_dl *sdl;
- struct rt_msghdr *rtm;
struct ether_addr *ea;
char *host = argv[0], *eaddr = argv[1];
struct sockaddr_dl sdl_m;
@@ -336,21 +333,17 @@
dst = getaddr(host);
if (dst == NULL)
return (1);
- doing_proxy = flags = expire_time = 0;
while (argc-- > 0) {
if (strcmp(argv[0], "temp") == 0) {
- struct timespec tp;
int max_age;
size_t len = sizeof(max_age);
- clock_gettime(CLOCK_MONOTONIC, &tp);
if (sysctlbyname("net.link.ether.inet.max_age",
&max_age, &len, NULL, 0) != 0)
xo_err(1, "sysctlbyname");
- expire_time = tp.tv_sec + max_age;
+ opts.expire_time = max_age;
} else if (strcmp(argv[0], "pub") == 0) {
- flags |= RTF_ANNOUNCE;
- doing_proxy = 1;
+ opts.flags |= RTF_ANNOUNCE;
if (argc && strcmp(argv[1], "only") == 0) {
/*
* Compatibility: in pre FreeBSD 8 times
@@ -361,17 +354,17 @@
argc--; argv++;
}
} else if (strcmp(argv[0], "blackhole") == 0) {
- if (flags & RTF_REJECT) {
+ if (opts.flags & RTF_REJECT) {
xo_errx(1, "Choose one of blackhole or reject, "
"not both.");
}
- flags |= RTF_BLACKHOLE;
+ opts.flags |= RTF_BLACKHOLE;
} else if (strcmp(argv[0], "reject") == 0) {
- if (flags & RTF_BLACKHOLE) {
+ if (opts.flags & RTF_BLACKHOLE) {
xo_errx(1, "Choose one of blackhole or reject, "
"not both.");
}
- flags |= RTF_REJECT;
+ opts.flags |= RTF_REJECT;
} else {
xo_warnx("Invalid parameter '%s'", argv[0]);
usage();
@@ -379,7 +372,7 @@
argv++;
}
ea = (struct ether_addr *)LLADDR(&sdl_m);
- if (doing_proxy && !strcmp(eaddr, "auto")) {
+ if ((opts.flags & RTF_ANNOUNCE) && !strcmp(eaddr, "auto")) {
if (!get_ether_addr(dst->sin_addr.s_addr, ea)) {
xo_warnx("no interface found for %s",
inet_ntoa(dst->sin_addr));
@@ -397,6 +390,20 @@
sdl_m.sdl_alen = ETHER_ADDR_LEN;
}
}
+#ifndef WITHOUT_NETLINK
+ return (set_nl(0, dst, &sdl_m, host));
+#else
+ return (set_rtsock(dst, &sdl_m, host));
+#endif
+}
+
+#ifdef WITHOUT_NETLINK
+static int
+set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m, char *host)
+{
+ struct sockaddr_in *addr;
+ struct sockaddr_dl *sdl;
+ struct rt_msghdr *rtm;
/*
* In the case a proxy-arp entry is being added for
@@ -420,10 +427,11 @@
xo_warnx("cannot intuit interface index and type for %s", host);
return (1);
}
- sdl_m.sdl_type = sdl->sdl_type;
- sdl_m.sdl_index = sdl->sdl_index;
- return (rtmsg(RTM_ADD, dst, &sdl_m) == NULL);
+ sdl_m->sdl_type = sdl->sdl_type;
+ sdl_m->sdl_index = sdl->sdl_index;
+ return (rtmsg(RTM_ADD, dst, sdl_m) == NULL);
}
+#endif
/*
* Display an individual arp entry
@@ -442,7 +450,7 @@
xo_open_container("arp");
xo_open_list("arp-cache");
- found = search(addr->sin_addr.s_addr, print_entry);
+ found = print_entries(0, addr->sin_addr);
if (found == 0) {
xo_emit("{d:hostname/%s} ({d:ip-address/%s}) -- no entry",
@@ -462,8 +470,9 @@
/*
* Delete an arp entry
*/
+#ifdef WITHOUT_NETLINK
static int
-delete(char *host)
+delete_rtsock(char *host)
{
struct sockaddr_in *addr, *dst;
struct rt_msghdr *rtm;
@@ -476,7 +485,7 @@
/*
* Perform a regular entry delete first.
*/
- flags &= ~RTF_ANNOUNCE;
+ opts.flags &= ~RTF_ANNOUNCE;
for (;;) { /* try twice */
rtm = rtmsg(RTM_GET, dst, NULL);
@@ -506,12 +515,12 @@
* Regular entry delete failed, now check if there
* is a proxy-arp entry to remove.
*/
- if (flags & RTF_ANNOUNCE) {
+ if (opts.flags & RTF_ANNOUNCE) {
xo_warnx("delete: cannot locate %s", host);
return (1);
}
- flags |= RTF_ANNOUNCE;
+ opts.flags |= RTF_ANNOUNCE;
}
rtm->rtm_flags |= RTF_LLDATA;
if (rtmsg(RTM_DELETE, dst, NULL) != NULL) {
@@ -520,6 +529,17 @@
}
return (1);
}
+#endif
+
+static int
+delete(char *host)
+{
+#ifdef WITHOUT_NETLINK
+ return (delete_rtsock(host));
+#else
+ return (delete_nl(0, host));
+#endif
+}
/*
@@ -600,7 +620,7 @@
xo_open_instance("arp-cache");
- if (nflag == 0)
+ if (!opts.nflag)
hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
sizeof addr->sin_addr, AF_INET);
else
@@ -610,7 +630,7 @@
else {
host = "?";
if (h_errno == TRY_AGAIN)
- nflag = 1;
+ opts.nflag = true;
}
xo_emit("{:hostname/%s} ({:ip-address/%s}) at ", host,
inet_ntoa(addr->sin_addr));
@@ -640,6 +660,8 @@
xo_emit("{d:/ permanent}{en:permanent/true}");
else {
static struct timespec tp;
+ time_t expire_time = 0;
+
if (tp.tv_sec == 0)
clock_gettime(CLOCK_MONOTONIC, &tp);
if ((expire_time = rtm->rtm_rmx.rmx_expire - tp.tv_sec) > 0)
@@ -683,6 +705,17 @@
xo_close_instance("arp-cache");
}
+static int
+print_entries(uint32_t ifindex, struct in_addr addr)
+{
+#ifndef WITHOUT_NETLINK
+ return (print_entries_nl(ifindex, addr));
+#else
+ return (search(addr.s_addr, print_entry));
+#endif
+}
+
+
/*
* Nuke an arp entry
*/
@@ -699,6 +732,12 @@
delete(ip);
}
+static void
+nuke_entries(uint32_t ifindex, struct in_addr addr)
+{
+ search(addr.s_addr, nuke_entry);
+}
+
static void
usage(void)
{
@@ -745,7 +784,7 @@
if (cmd == RTM_DELETE)
goto doit;
bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
- rtm->rtm_flags = flags;
+ rtm->rtm_flags = opts.flags;
rtm->rtm_version = RTM_VERSION;
switch (cmd) {
@@ -753,7 +792,12 @@
xo_errx(1, "internal wrong cmd");
case RTM_ADD:
rtm->rtm_addrs |= RTA_GATEWAY;
- rtm->rtm_rmx.rmx_expire = expire_time;
+ if (opts.expire_time != 0) {
+ struct timespec tp;
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ rtm->rtm_rmx.rmx_expire = opts.expire_time + tp.tv_sec;
+ }
rtm->rtm_inits = RTV_EXPIRE;
rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
/* FALLTHROUGH */
diff --git a/usr.sbin/arp/arp_netlink.c b/usr.sbin/arp/arp_netlink.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/arp/arp_netlink.c
@@ -0,0 +1,433 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include <sys/bitcount.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netlink/netlink.h>
+#include <netlink/netlink_route.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_route.h>
+#include <netlink/netlink_snl_route_compat.h>
+#include <netlink/netlink_snl_route_parsers.h>
+
+#include <libxo/xo.h>
+#include "arp.h"
+
+#define RTF_ANNOUNCE RTF_PROTO2
+
+static void
+nl_init_socket(struct snl_state *ss)
+{
+ if (snl_init(ss, NETLINK_ROUTE))
+ return;
+
+ if (modfind("netlink") == -1 && errno == ENOENT) {
+ /* Try to load */
+ if (kldload("netlink") == -1)
+ err(1, "netlink is not loaded and load attempt failed");
+ if (snl_init(ss, NETLINK_ROUTE))
+ return;
+ }
+
+ err(1, "unable to open netlink socket");
+}
+
+static bool
+get_link_info(struct snl_state *ss, uint32_t ifindex,
+ struct snl_parsed_link_simple *link)
+{
+ struct snl_writer nw;
+
+ snl_init_writer(ss, &nw);
+
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK);
+ struct ifinfomsg *ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg);
+ if (ifmsg != NULL)
+ ifmsg->ifi_index = ifindex;
+ if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr))
+ return (false);
+
+ hdr = snl_read_reply(ss, hdr->nlmsg_seq);
+
+ if (hdr == NULL || hdr->nlmsg_type != RTM_NEWLINK)
+ return (false);
+
+ if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, link))
+ return (false);
+
+ return (true);
+}
+
+
+
+static bool
+has_l2(struct snl_state *ss, uint32_t ifindex)
+{
+ struct snl_parsed_link_simple link = {};
+
+ if (!get_link_info(ss, ifindex, &link))
+ return (false);
+
+ return (valid_type(link.ifi_type) != 0);
+}
+
+static uint32_t
+get_myfib()
+{
+ uint32_t fibnum = 0;
+ size_t len = sizeof(fibnum);
+
+ sysctlbyname("net.my_fibnum", (void *)&fibnum, &len, NULL, 0);
+
+ return (fibnum);
+}
+
+static int
+guess_ifindex(struct snl_state *ss, uint32_t fibnum, struct in_addr addr)
+{
+ struct snl_writer nw;
+
+ snl_init_writer(ss, &nw);
+
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETROUTE);
+ struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg);
+ rtm->rtm_family = AF_INET;
+
+ struct sockaddr_in dst = { .sin_family = AF_INET, .sin_addr = addr };
+ snl_add_msg_attr_ip(&nw, RTA_DST, (struct sockaddr *)&dst);
+ snl_add_msg_attr_u32(&nw, RTA_TABLE, fibnum);
+
+ if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr))
+ return (0);
+
+ hdr = snl_read_reply(ss, hdr->nlmsg_seq);
+
+ if (hdr->nlmsg_type != NL_RTM_NEWROUTE) {
+ /* No route found, unable to guess ifindex */
+ return (0);
+ }
+
+ struct snl_parsed_route r = {};
+ if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r))
+ return (0);
+
+ if (r.rta_multipath || (r.rta_rtflags & RTF_GATEWAY))
+ return (0);
+
+ /* Check if the interface is of supported type */
+ if (has_l2(ss, r.rta_oif))
+ return (r.rta_oif);
+
+ /* Check the case when we matched the loopback route for P2P */
+ snl_init_writer(ss, &nw);
+ hdr = snl_create_msg_request(&nw, RTM_GETNEXTHOP);
+ snl_reserve_msg_object(&nw, struct nhmsg);
+
+ int off = snl_add_msg_attr_nested(&nw, NHA_FREEBSD);
+ snl_add_msg_attr_u32(&nw, NHAF_KID, r.rta_knh_id);
+ snl_add_msg_attr_u8(&nw, NHAF_FAMILY, AF_INET);
+ snl_add_msg_attr_u32(&nw, NHAF_TABLE, fibnum);
+ snl_end_attr_nested(&nw, off);
+
+ if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr))
+ return (0);
+
+ hdr = snl_read_reply(ss, hdr->nlmsg_seq);
+
+ if (hdr->nlmsg_type != NL_RTM_NEWNEXTHOP) {
+ /* No nexthop found, unable to guess ifindex */
+ return (0);
+ }
+
+ struct snl_parsed_nhop nh = {};
+ if (!snl_parse_nlmsg(ss, hdr, &snl_nhmsg_parser, &nh))
+ return (0);
+
+ return (nh.nhaf_aif);
+}
+
+static uint32_t
+fix_ifindex(struct snl_state *ss, uint32_t ifindex, struct in_addr addr)
+{
+ if (ifindex == 0)
+ ifindex = guess_ifindex(ss, get_myfib(), addr);
+ return (ifindex);
+}
+
+static void
+print_entry(struct snl_parsed_neigh *neigh, struct snl_parsed_link_simple *link)
+{
+ const char *host;
+ struct hostent *hp;
+ struct sockaddr_in *addr = (struct sockaddr_in *)neigh->nda_dst;
+
+ xo_open_instance("arp-cache");
+
+ if (!opts.nflag)
+ hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
+ sizeof(addr->sin_addr), AF_INET);
+ else
+ hp = 0;
+ if (hp)
+ host = hp->h_name;
+ else {
+ host = "?";
+ if (h_errno == TRY_AGAIN)
+ opts.nflag = true;
+ }
+ xo_emit("{:hostname/%s} ({:ip-address/%s}) at ", host,
+ inet_ntoa(addr->sin_addr));
+ if (neigh->nda_lladdr != NULL) {
+ struct sockaddr_dl sdl = {
+ .sdl_family = AF_LINK,
+ .sdl_type = link->ifi_type,
+ .sdl_len = sizeof(struct sockaddr_dl),
+ .sdl_alen = NLA_DATA_LEN(neigh->nda_lladdr),
+ };
+ memcpy(sdl.sdl_data, NLA_DATA(neigh->nda_lladdr), sdl.sdl_alen);
+
+ if ((sdl.sdl_type == IFT_ETHER ||
+ sdl.sdl_type == IFT_L2VLAN ||
+ sdl.sdl_type == IFT_BRIDGE) &&
+ sdl.sdl_alen == ETHER_ADDR_LEN)
+ xo_emit("{:mac-address/%s}",
+ ether_ntoa((struct ether_addr *)LLADDR(&sdl)));
+ else {
+
+ xo_emit("{:mac-address/%s}", link_ntoa(&sdl));
+ }
+ } else
+ xo_emit("{d:/(incomplete)}{en:incomplete/true}");
+ xo_emit(" on {:interface/%s}", link->ifla_ifname);
+
+ if (neigh->ndaf_next_ts == 0)
+ xo_emit("{d:/ permanent}{en:permanent/true}");
+ else {
+ time_t expire_time;
+ struct timeval now;
+
+ gettimeofday(&now, 0);
+ if ((expire_time = neigh->ndaf_next_ts - now.tv_sec) > 0)
+ xo_emit(" expires in {:expires/%d} seconds",
+ (int)expire_time);
+ else
+ xo_emit("{d:/ expired}{en:expired/true}");
+ }
+
+ if (neigh->ndm_flags & NTF_PROXY)
+ xo_emit("{d:/ published}{en:published/true}");
+
+ switch(link->ifi_type) {
+ case IFT_ETHER:
+ xo_emit(" [{:type/ethernet}]");
+ break;
+ case IFT_FDDI:
+ xo_emit(" [{:type/fddi}]");
+ break;
+ case IFT_ATM:
+ xo_emit(" [{:type/atm}]");
+ break;
+ case IFT_L2VLAN:
+ xo_emit(" [{:type/vlan}]");
+ break;
+ case IFT_IEEE1394:
+ xo_emit(" [{:type/firewire}]");
+ break;
+ case IFT_BRIDGE:
+ xo_emit(" [{:type/bridge}]");
+ break;
+ case IFT_INFINIBAND:
+ xo_emit(" [{:type/infiniband}]");
+ break;
+ default:
+ break;
+ }
+
+ xo_emit("\n");
+
+ xo_close_instance("arp-cache");
+}
+
+int
+print_entries_nl(uint32_t ifindex, struct in_addr addr)
+{
+ struct snl_state ss_req = {}, ss_cmd = {};
+ struct snl_parsed_link_simple link = {};
+ struct snl_writer nw;
+
+ nl_init_socket(&ss_req);
+ snl_init_writer(&ss_req, &nw);
+
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETNEIGH);
+ struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg);
+ if (ndmsg != NULL) {
+ ndmsg->ndm_family = AF_INET;
+ ndmsg->ndm_ifindex = ifindex;
+ }
+
+ if (!snl_finalize_msg(&nw) || !snl_send_message(&ss_req, hdr)) {
+ snl_free(&ss_req);
+ return (0);
+ }
+
+ uint32_t nlmsg_seq = hdr->nlmsg_seq;
+ struct snl_errmsg_data e = {};
+ int count = 0;
+ nl_init_socket(&ss_cmd);
+
+ while ((hdr = snl_read_reply_multi(&ss_req, nlmsg_seq, &e)) != NULL) {
+ struct snl_parsed_neigh neigh = {};
+
+ if (!snl_parse_nlmsg(&ss_req, hdr, &snl_rtm_neigh_parser, &neigh))
+ continue;
+
+ if (neigh.nda_ifindex != link.ifi_index) {
+ snl_clear_lb(&ss_cmd);
+ memset(&link, 0, sizeof(link));
+ if (!get_link_info(&ss_cmd, neigh.nda_ifindex, &link))
+ continue;
+ }
+
+ print_entry(&neigh, &link);
+ count++;
+ snl_clear_lb(&ss_req);
+ }
+
+ snl_free(&ss_req);
+ snl_free(&ss_cmd);
+
+ return (count);
+}
+
+int
+delete_nl(uint32_t ifindex, char *host)
+{
+ struct snl_state ss = {};
+ struct snl_writer nw;
+ struct sockaddr_in *dst;
+
+ dst = getaddr(host);
+ if (dst == NULL)
+ return (1);
+
+ nl_init_socket(&ss);
+
+ ifindex = fix_ifindex(&ss, ifindex, dst->sin_addr);
+ if (ifindex == 0) {
+ xo_warnx("delete: cannot locate %s", host);
+ snl_free(&ss);
+ return (0);
+ }
+
+ snl_init_writer(&ss, &nw);
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_DELNEIGH);
+ struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg);
+ if (ndmsg != NULL) {
+ ndmsg->ndm_family = AF_INET;
+ ndmsg->ndm_ifindex = ifindex;
+ }
+ snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)dst);
+
+ if (!snl_finalize_msg(&nw) || !snl_send_message(&ss, hdr)) {
+ snl_free(&ss);
+ return (1);
+ }
+
+ struct snl_errmsg_data e = {};
+ snl_read_reply_code(&ss, hdr->nlmsg_seq, &e);
+ if (e.error != 0) {
+ if (e.error_str != NULL)
+ xo_warnx("delete %s: %s (%s)", host, strerror(e.error), e.error_str);
+ else
+ xo_warnx("delete %s: %s", host, strerror(e.error));
+ }
+ snl_free(&ss);
+
+ return (e.error != 0);
+}
+
+int
+set_nl(uint32_t ifindex, struct sockaddr_in *dst, struct sockaddr_dl *sdl, char *host)
+{
+ struct snl_state ss = {};
+ struct snl_writer nw;
+
+ nl_init_socket(&ss);
+
+ ifindex = fix_ifindex(&ss, ifindex, dst->sin_addr);
+ if (ifindex == 0) {
+ xo_warnx("delete: cannot locate %s", host);
+ snl_free(&ss);
+ return (0);
+ }
+
+ if (opts.expire_time != 0)
+ opts.flags &= ~RTF_STATIC;
+ printf("EXPIRE: %ld\n", opts.expire_time);
+
+ snl_init_writer(&ss, &nw);
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_NEWNEIGH);
+ hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+ struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg);
+ if (ndmsg != NULL) {
+ uint8_t nl_flags = 0;
+
+ ndmsg->ndm_family = AF_INET;
+ ndmsg->ndm_ifindex = ifindex;
+ ndmsg->ndm_state = (opts.flags & RTF_STATIC) ? NUD_PERMANENT : NUD_NONE;
+
+ if (opts.flags & RTF_ANNOUNCE)
+ nl_flags |= NTF_PROXY;
+ if (opts.flags & RTF_STATIC)
+ nl_flags |= NTF_STICKY;
+ ndmsg->ndm_flags = nl_flags;
+ }
+ snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)dst);
+ snl_add_msg_attr(&nw, NDA_LLADDR, sdl->sdl_alen, LLADDR(sdl));
+
+ if (opts.expire_time != 0) {
+ struct timeval now;
+
+ gettimeofday(&now, 0);
+ int off = snl_add_msg_attr_nested(&nw, NDA_FREEBSD);
+ snl_add_msg_attr_u32(&nw, NDAF_NEXT_STATE_TS, now.tv_sec + opts.expire_time);
+ snl_end_attr_nested(&nw, off);
+ }
+
+ if (!snl_finalize_msg(&nw) || !snl_send_message(&ss, hdr)) {
+ snl_free(&ss);
+ return (1);
+ }
+
+ struct snl_errmsg_data e = {};
+ snl_read_reply_code(&ss, hdr->nlmsg_seq, &e);
+ if (e.error != 0) {
+ if (e.error_str != NULL)
+ xo_warnx("set: %s: %s (%s)", host, strerror(e.error), e.error_str);
+ else
+ xo_warnx("set %s: %s", host, strerror(e.error));
+ }
+ snl_free(&ss);
+
+ return (e.error != 0);
+}
+
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, May 16, 7:04 PM (1 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33145879
Default Alt Text
D39720.id120994.diff (20 KB)
Attached To
Mode
D39720: nelink: convert arp/ndp to use netlink interfaces
Attached
Detach File
Event Timeline
Log In to Comment