I find arp(8) output really difficult to read, but more importantly it
does not print the expire time of non permanent entries like ndp(8).

So the diff below change arp(8)'s output to be more similar to ndp(8)'s
one.

Before:

$ arp -a
? (10.0.5.1) at 00:72:17:ab:94:3e on vlan3 static
? (10.0.5.3) at (incomplete) on vlan3
? (10.0.5.41) at 00:90:27:bb:cc:dd on vlan3 permanent static
? (10.0.5.42) at 00:90:27:bb:cc:dd on vlan3 static published
? (10.0.5.255) at (incomplete) on vlan3 static
? (10.3.3.9) at 00:72:17:ab:94:3e on vlan3 static
? (10.3.3.255) at (incomplete) on vlan3 static
? (192.168.6.1) at 00:72:17:ab:94:3e on em1 static
? (192.168.6.255) at (incomplete) on em1 static
dizzy (192.168.172.111) at 00:2f:c6:55:8b:dd on em0
DHCP-225.inside.wafwaf.net (192.168.172.225) at 00:32:68:ba:4c:dd on em0 static
radar.inside.wafwaf.net (192.168.172.249) at 00:2f:fe:f4:0f:00 on em0
dns.inside.wafwaf.net (192.168.172.254) at 00:20:28:a6:96:a0 on em0
? (192.168.172.255) at (incomplete) on em0 static


After: 

$ arp -a                      
Host                                 Ethernet Address   Netif Expire     Flags
10.0.5.1                             0:72:17:ab:94:3e   vlan3 static      
10.0.5.3                             (incomplete)       vlan3 expired    
10.0.5.41                            0:90:27:bb:cc:dd   vlan3 permanent
10.0.5.42                            0:90:27:bb:cc:dd   vlan3 static     p
10.0.5.255                           (incomplete)       vlan3 static     
10.3.3.9                             0:72:17:ab:94:3e   vlan3 static     
10.3.3.255                           (incomplete)       vlan3 static     
192.168.6.1                          0:72:17:ab:94:3e     em1 static     
192.168.6.255                        (incomplete)         em1 static     
dizzy                                0:2f:c6:55:8b:dd     em0 10m54s     
dhcp.inside.wafwaf.net               0:32:68:ba:4c:dd     em0 static     
radar.inside.wafwaf.net              0:2f:fe:f4:f:0       em0 20s     
dns.inside.wafwaf.net                0:20:28:a6:96:a0     em0 10m54s     
192.168.172.255                      (incomplete)         em0 static 

Does anybody parse the output of arp(8)?  Is it a concern?  Ok?

Index: arp.8
===================================================================
RCS file: /home/ncvs/src/usr.sbin/arp/arp.8,v
retrieving revision 1.33
diff -u -p -r1.33 arp.8
--- arp.8       9 May 2014 06:37:38 -0000       1.33
+++ arp.8       12 Aug 2014 13:23:11 -0000
@@ -79,6 +79,31 @@ Display all of the current ARP entries.
 See also the
 .Fl d
 option below.
+The following information will be printed:
+.Bl -tag -width Ds -offset 3n
+.It Host
+The network address of the host.
+.It Ethernet Address
+The Ethernet address of the host.
+If the address is not available,
+it will be displayed as
+.Dq (incomplete) .
+.It Netif
+The network interface associated with the ARP entry.
+.It Expire
+The time until expiry of the entry.
+If the entry is marked
+.Dq permanent
+or
+.Dq static ,
+it will never expire.
+.It Flags
+Flags on the ARP entry, in a single letter.
+They are: proxy
+.Pq Sq P
+and published
+.Pq Sq p .
+.El
 .It Fl d
 Delete an entry for the host called
 .Ar hostname .
Index: arp.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/arp/arp.c,v
retrieving revision 1.57
diff -u -p -r1.57 arp.c
--- arp.c       11 Aug 2014 09:47:56 -0000      1.57
+++ arp.c       12 Aug 2014 13:23:11 -0000
@@ -61,6 +61,7 @@
 #include <unistd.h>
 #include <ifaddrs.h>
 
+void dump(void);
 int delete(const char *, const char *);
 void search(in_addr_t addr, void (*action)(struct sockaddr_dl *sdl,
        struct sockaddr_inarp *sin, struct rt_msghdr *rtm));
@@ -68,8 +69,8 @@ void print_entry(struct sockaddr_dl *sdl
        struct sockaddr_inarp *sin, struct rt_msghdr *rtm);
 void nuke_entry(struct sockaddr_dl *sdl,
        struct sockaddr_inarp *sin, struct rt_msghdr *rtm);
+static char *ether_str(struct sockaddr_dl *);
 int wake(const char *ether_addr, const char *iface);
-void ether_print(const char *);
 int file(char *);
 int get(const char *);
 int getinetaddr(const char *, struct in_addr *);
@@ -77,6 +78,7 @@ void getsocket(void);
 int rtmsg(int);
 int set(int, char **);
 void usage(void);
+static char *sec2str(time_t);
 
 static pid_t pid;
 static int replace;    /* replace entries when adding */
@@ -160,7 +162,7 @@ main(int argc, char *argv[])
        switch (func) {
        case F_GET:
                if (aflag && argc == 0)
-                       search(0, print_entry);
+                       dump();
                else if (!aflag && argc == 1)
                        rtn = get(argv[0]);
                else
@@ -360,6 +362,10 @@ overwrite:
        return (rtmsg(RTM_ADD));
 }
 
+#define W_ADDR 36
+#define W_LL   17
+#define W_IF   6
+
 /*
  * Display an individual arp entry
  */
@@ -372,9 +378,15 @@ get(const char *host)
        sin_m = blank_sin;              /* struct copy */
        if (getinetaddr(host, &sin->sin_addr) == -1)
                exit(1);
+
+       printf("%-*.*s %-*.*s %*.*s %-10.10s %5s\n",
+           W_ADDR, W_ADDR, "Host", W_LL, W_LL, "Ethernet Address",
+           W_IF, W_IF, "Netif", "Expire", "Flags");
+
        search(sin->sin_addr.s_addr, print_entry);
        if (found_entry == 0) {
-               printf("%s (%s) -- no entry\n", host, inet_ntoa(sin->sin_addr));
+               printf("%-*.*s no entry\n", W_ADDR, W_ADDR,
+                   inet_ntoa(sin->sin_addr));
                return (1);
        }
        return (0);
@@ -494,49 +506,72 @@ search(in_addr_t addr, void (*action)(st
 }
 
 /*
+ * Dump the entire ARP table
+ */
+void
+dump(void)
+{
+       printf("%-*.*s %-*.*s %*.*s %-10.10s %5s\n",
+           W_ADDR, W_ADDR, "Host", W_LL, W_LL, "Ethernet Address",
+           W_IF, W_IF, "Netif", "Expire", "Flags");
+
+       search(0, print_entry);
+}
+
+/*
  * Display an arp entry
  */
 void
 print_entry(struct sockaddr_dl *sdl, struct sockaddr_inarp *sin,
     struct rt_msghdr *rtm)
 {
-       char ifname[IFNAMSIZ], *host;
-       struct hostent *hp;
+       char ifix_buf[IFNAMSIZ], *ifname, *host;
+       struct hostent *hp = NULL;
+       int addrwidth, llwidth, ifwidth ;
+       struct timeval now;
+       char flgbuf[8];
+
+       gettimeofday(&now, 0);
 
        if (nflag == 0)
                hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
                    sizeof(sin->sin_addr), AF_INET);
-       else
-               hp = 0;
        if (hp)
                host = hp->h_name;
-       else {
-               host = "?";
-               if (h_errno == TRY_AGAIN)
-                       nflag = 1;
-       }
-       printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
-       if (sdl->sdl_alen)
-               ether_print(LLADDR(sdl));
        else
-               printf("(incomplete)");
-       if (if_indextoname(sdl->sdl_index, ifname) != NULL)
-               printf(" on %s", ifname);
+               host = inet_ntoa(sin->sin_addr);
+
+       addrwidth = strlen(host);
+       if (addrwidth < W_ADDR)
+               addrwidth = W_ADDR;
+       llwidth = strlen(ether_str(sdl));
+       if (W_ADDR + W_LL - addrwidth > llwidth)
+               llwidth = W_ADDR + W_LL - addrwidth;
+       ifname = if_indextoname(sdl->sdl_index, ifix_buf);
+       if (!ifname)
+               ifname = "?";
+       ifwidth = strlen(ifname);
+       if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
+               ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
+
+       printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host,
+           llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
+
        if (rtm->rtm_flags & RTF_PERMANENT_ARP)
-               printf(" permanent");
-       if (rtm->rtm_rmx.rmx_expire == 0)
-               printf(" static");
-       if (sin->sin_other & SIN_PROXY)
-               printf(" published (proxy only)");
-       if (rtm->rtm_addrs & RTA_NETMASK) {
-               sin = (struct sockaddr_inarp *)
-                   (ROUNDUP(sdl->sdl_len) + (char *)sdl);
-               if (sin->sin_addr.s_addr == 0xffffffff)
-                       printf(" published");
-               if (sin->sin_len != 8)
-                       printf("(weird %d)", sin->sin_len);
-       }
-       printf("\n");
+               printf(" %-10.10s", "permanent");
+       else if (rtm->rtm_rmx.rmx_expire == 0)
+               printf(" %-10.10s", "static");
+       else if (rtm->rtm_rmx.rmx_expire > now.tv_sec)
+               printf(" %-10.10s",
+                   sec2str(rtm->rtm_rmx.rmx_expire - now.tv_sec));
+       else
+               printf(" %-10.10s", "expired");
+
+       snprintf(flgbuf, sizeof(flgbuf), "%s%s",
+           (sin->sin_other & SIN_PROXY) ? "P" : "",
+           (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+
+       printf(" %s\n", flgbuf);
 }
 
 /*
@@ -552,13 +587,20 @@ nuke_entry(struct sockaddr_dl *sdl, stru
        delete(ip, NULL);
 }
 
-void
-ether_print(const char *scp)
+static char *
+ether_str(struct sockaddr_dl *sdl)
 {
-       const u_char *cp = (u_char *)scp;
+       static char hbuf[NI_MAXHOST];
+       u_char *cp;
+
+       if (sdl->sdl_alen) {
+               cp = (u_char *)LLADDR(sdl);
+               snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x",
+                   cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+       } else
+               snprintf(hbuf, sizeof(hbuf), "(incomplete)");
 
-       printf("%02x:%02x:%02x:%02x:%02x:%02x",
-           cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+       return(hbuf);
 }
 
 void
@@ -659,6 +701,47 @@ getinetaddr(const char *host, struct in_
        }
        memcpy(inap, hp->h_addr, sizeof(*inap));
        return (0);
+}
+
+static char *
+sec2str(time_t total)
+{
+       static char result[256];
+       int days, hours, mins, secs;
+       int first = 1;
+       char *p = result;
+       char *ep = &result[sizeof(result)];
+       int n;
+
+       days = total / 3600 / 24;
+       hours = (total / 3600) % 24;
+       mins = (total / 60) % 60;
+       secs = total % 60;
+
+       if (days) {
+               first = 0;
+               n = snprintf(p, ep - p, "%dd", days);
+               if (n < 0 || n >= ep - p)
+                       return "?";
+               p += n;
+       }
+       if (!first || hours) {
+               first = 0;
+               n = snprintf(p, ep - p, "%dh", hours);
+               if (n < 0 || n >= ep - p)
+                       return "?";
+               p += n;
+       }
+       if (!first || mins) {
+               first = 0;
+               n = snprintf(p, ep - p, "%dm", mins);
+               if (n < 0 || n >= ep - p)
+                       return "?";
+               p += n;
+       }
+       snprintf(p, ep - p, "%ds", secs);
+
+       return(result);
 }
 
 /*

Reply via email to