From e1ee6c49fa7fa2b7b712319c160ab998ffa1957f Mon Sep 17 00:00:00 2001 From: mpi Date: Thu, 21 Aug 2014 10:23:47 +0000 Subject: [PATCH] Change the output of arp(8) to match what ndp(8) does and include the expire timer. This will makes it easier to add further information in a coherent way between these tools for local and broadcast entries. This new view displays either symbolic names (by default) or numerical addresses (with "-n") for hosts but not both at the same time, just like ndp(8), route(8) or netstat(1) do. ok henning@ --- usr.sbin/arp/arp.8 | 29 ++++++++- usr.sbin/arp/arp.c | 159 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 148 insertions(+), 40 deletions(-) diff --git a/usr.sbin/arp/arp.8 b/usr.sbin/arp/arp.8 index 26b1c3c9eea..620249b6a8c 100644 --- a/usr.sbin/arp/arp.8 +++ b/usr.sbin/arp/arp.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: arp.8,v 1.33 2014/05/09 06:37:38 jmc Exp $ +.\" $OpenBSD: arp.8,v 1.34 2014/08/21 10:23:47 mpi Exp $ .\" $NetBSD: arp.8,v 1.7 1995/03/01 11:50:59 chopps Exp $ .\" .\" Copyright (c) 1985, 1991, 1993 @@ -30,7 +30,7 @@ .\" .\" from: @(#)arp.8 8.1 (Berkeley) 6/6/93 .\" -.Dd $Mdocdate: May 9 2014 $ +.Dd $Mdocdate: August 21 2014 $ .Dt ARP 8 .Os .Sh NAME @@ -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 . diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c index 19a6d13519f..ffb45e239c9 100644 --- a/usr.sbin/arp/arp.c +++ b/usr.sbin/arp/arp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arp.c,v 1.58 2014/08/19 12:39:36 mpi Exp $ */ +/* $OpenBSD: arp.c,v 1.59 2014/08/21 10:23:47 mpi Exp $ */ /* $NetBSD: arp.c,v 1.12 1995/04/24 13:25:18 cgd Exp $ */ /* @@ -61,6 +61,7 @@ #include #include +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); @@ -493,6 +505,19 @@ search(in_addr_t addr, void (*action)(struct sockaddr_dl *sdl, free(buf); } +/* + * 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 */ @@ -500,43 +525,53 @@ 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, struct sockaddr_inarp *sin, 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 @@ -661,6 +703,47 @@ getinetaddr(const char *host, struct in_addr *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); +} + /* * Copyright (c) 2011 Jasper Lievisse Adriaanse * Copyright (C) 2006,2007,2008,2009 Marc Balmer -- 2.20.1