The branch main has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=79278872ad966e5f54805efbeb692c8cbc0306c8

commit 79278872ad966e5f54805efbeb692c8cbc0306c8
Author:     R. Christian McDonald <r...@rcm.sh>
AuthorDate: 2023-09-14 07:07:24 +0000
Commit:     Kristof Provost <k...@freebsd.org>
CommitDate: 2023-09-14 08:14:10 +0000

    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")
---
 usr.sbin/arp/arp.c         | 34 +++++++++++++++-------------------
 usr.sbin/arp/arp.h         |  2 ++
 usr.sbin/arp/arp_netlink.c |  8 ++++++++
 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);

Reply via email to