aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorR. Christian McDonald <rcm@rcm.sh>2023-09-14 07:07:24 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2023-09-30 13:26:12 +0000
commitf21f0d2e16af702c53bc150c6c23d1bc99399bcd (patch)
tree3e96ca32b460ba3780e2d04dc9f11f89f8525ea5
parent0cf6ebad73640a20fe99adacba635e2630be5d08 (diff)
downloadsrc-f21f0d2e16af702c53bc150c6c23d1bc99399bcd.tar.gz
src-f21f0d2e16af702c53bc150c6c23d1bc99399bcd.zip
arp(8): fix by-interface and by-host filtering when using netlink
arp(8) has traditionally supported filtering by interface via -i and by hostname. However, this functionality was omitted from the initial netlink-ification of arp. This patch re-introduces this filtering functionality. This patch also improves by-interface filtering by storing and using the ifindex of the requested interface for filtering instead of comparing interface name strings Reviewed by: melifaro Sponsored by: Rubicon Communications, LLC ("Netgate") (cherry picked from commit 79278872ad966e5f54805efbeb692c8cbc0306c8)
-rw-r--r--usr.sbin/arp/arp.c34
-rw-r--r--usr.sbin/arp/arp.h2
-rw-r--r--usr.sbin/arp/arp_netlink.c8
3 files changed, 25 insertions, 19 deletions
diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c
index 02b2bb1ac4f8..9a19d792f788 100644
--- a/usr.sbin/arp/arp.c
+++ b/usr.sbin/arp/arp.c
@@ -98,8 +98,6 @@ static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr);
static int set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m,
char *host);
-static char *rifname;
-
struct if_nameindex *ifnameindex;
struct arp_opts opts = {};
@@ -146,7 +144,7 @@ main(int argc, char *argv[])
SETFUNC(F_FILESET);
break;
case 'i':
- rifname = optarg;
+ opts.rifname = optarg;
break;
case '?':
default:
@@ -157,15 +155,15 @@ main(int argc, char *argv[])
if (!func)
func = F_GET;
- if (rifname) {
+ if (opts.rifname) {
if (func != F_GET && !(func == F_DELETE && opts.aflag))
xo_errx(1, "-i not applicable to this operation");
- if (if_nametoindex(rifname) == 0) {
+ if ((opts.rifindex = if_nametoindex(opts.rifname)) == 0) {
if (errno == ENXIO)
xo_errx(1, "interface %s does not exist",
- rifname);
+ opts.rifname);
else
- xo_err(1, "if_nametoindex(%s)", rifname);
+ xo_err(1, "if_nametoindex(%s)", opts.rifname);
}
}
switch (func) {
@@ -179,7 +177,7 @@ main(int argc, char *argv[])
xo_open_list("arp-cache");
struct in_addr all_addrs = {};
- print_entries(0, all_addrs);
+ print_entries(opts.rifindex, all_addrs);
xo_close_list("arp-cache");
xo_close_container("arp");
@@ -448,13 +446,13 @@ get(char *host)
xo_open_container("arp");
xo_open_list("arp-cache");
- found = print_entries(0, addr->sin_addr);
+ found = print_entries(opts.rifindex, addr->sin_addr);
if (found == 0) {
xo_emit("{d:hostname/%s} ({d:ip-address/%s}) -- no entry",
host, inet_ntoa(addr->sin_addr));
- if (rifname)
- xo_emit(" on {d:interface/%s}", rifname);
+ if (opts.rifname)
+ xo_emit(" on {d:interface/%s}", opts.rifname);
xo_emit("\n");
}
@@ -552,7 +550,6 @@ search(u_long addr, action_fn *action)
struct rt_msghdr *rtm;
struct sockaddr_in *sin2;
struct sockaddr_dl *sdl;
- char ifname[IF_NAMESIZE];
int st, found_entry = 0;
mib[0] = CTL_NET;
@@ -586,14 +583,13 @@ search(u_long addr, action_fn *action)
rtm = (struct rt_msghdr *)next;
sin2 = (struct sockaddr_in *)(rtm + 1);
sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
- if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
- strcmp(ifname, rifname))
+ if (opts.rifindex &&
+ (opts.rifindex != sdl->sdl_index))
continue;
- if (addr) {
- if (addr != sin2->sin_addr.s_addr)
- continue;
- found_entry = 1;
- }
+ if (addr &&
+ (addr != sin2->sin_addr.s_addr))
+ continue;
+ found_entry = 1;
(*action)(sdl, sin2, rtm);
}
free(buf);
diff --git a/usr.sbin/arp/arp.h b/usr.sbin/arp/arp.h
index a7de3a1a3024..487863be43e7 100644
--- a/usr.sbin/arp/arp.h
+++ b/usr.sbin/arp/arp.h
@@ -10,6 +10,8 @@ struct arp_opts {
bool nflag;
time_t expire_time;
int flags;
+ char *rifname;
+ unsigned int rifindex;
};
extern struct arp_opts opts;
diff --git a/usr.sbin/arp/arp_netlink.c b/usr.sbin/arp/arp_netlink.c
index 4e5c8f3d9940..40b5367f330d 100644
--- a/usr.sbin/arp/arp_netlink.c
+++ b/usr.sbin/arp/arp_netlink.c
@@ -281,6 +281,7 @@ print_entries_nl(uint32_t ifindex, struct in_addr addr)
struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg);
if (ndmsg != NULL) {
ndmsg->ndm_family = AF_INET;
+ /* let kernel filter results by interface if provided */
ndmsg->ndm_ifindex = ifindex;
}
@@ -296,6 +297,7 @@ print_entries_nl(uint32_t ifindex, struct in_addr addr)
while ((hdr = snl_read_reply_multi(&ss_req, nlmsg_seq, &e)) != NULL) {
struct snl_parsed_neigh neigh = {};
+ struct sockaddr_in *neighaddr;
if (!snl_parse_nlmsg(&ss_req, hdr, &snl_rtm_neigh_parser, &neigh))
continue;
@@ -307,6 +309,12 @@ print_entries_nl(uint32_t ifindex, struct in_addr addr)
continue;
}
+ /* filter results based on host if provided */
+ neighaddr = (struct sockaddr_in *)neigh.nda_dst;
+ if (addr.s_addr &&
+ (addr.s_addr != neighaddr->sin_addr.s_addr))
+ continue;
+
print_entry(&neigh, &link);
count++;
snl_clear_lb(&ss_req);