From marck@woozle.rinet.ru  Sun Jul  6 09:15:56 2003
Return-Path: <marck@woozle.rinet.ru>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 811C237B401
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  6 Jul 2003 09:15:56 -0700 (PDT)
Received: from woozle.rinet.ru (woozle.rinet.ru [195.54.192.68])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 3B22F4402F
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  6 Jul 2003 09:15:55 -0700 (PDT)
	(envelope-from marck@woozle.rinet.ru)
Received: from woozle.rinet.ru (localhost [127.0.0.1])
	by woozle.rinet.ru (8.12.9/8.12.9) with ESMTP id h66GFsso020533
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 6 Jul 2003 20:15:54 +0400 (MSD)
	(envelope-from marck@woozle.rinet.ru)
Received: (from marck@localhost)
	by woozle.rinet.ru (8.12.9/8.12.9/Submit) id h66GFsBe020532;
	Sun, 6 Jul 2003 20:15:54 +0400 (MSD)
Message-Id: <200307061615.h66GFsBe020532@woozle.rinet.ru>
Date: Sun, 6 Jul 2003 20:15:54 +0400 (MSD)
From: Dmitry Morozovsky <marck@rinet.ru>
Reply-To: Dmitry Morozovsky <marck@rinet.ru>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [PATCH] -i (restrict to one interface) patch from arp(8)
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         54151
>Category:       bin
>Synopsis:       [PATCH] -i (restrict to one interface) patch from arp(8)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    yar
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jul 06 09:20:16 PDT 2003
>Closed-Date:    Fri Aug 01 06:31:44 PDT 2003
>Last-Modified:  Fri Aug 01 06:31:44 PDT 2003
>Originator:     Dmitry Morozovsky
>Release:        FreeBSD 4-STABLE i386
>Organization:
Cronyx Plus LLC (RiNet ISP)
>Environment:
System: FreeBSD 4-STABLE 


>Description:

Router with many ARP-enabled interfaces, such as inter-vlan router may have
very long ARP table. It is very usefult to have ability to view ARP table for
one onterface. Provided patches implements -i option and may be applied both to
-STABLE and -CURRENT.

The second patch adds checking for interface existance (I'm not sure whether
it's worth to blow /usr/sbin/arp with this check, so make it as independent
patch).

>How-To-Repeat:

>Fix:

*** PATCH 1

Index: usr.sbin/arp/arp.8
===================================================================
RCS file: /home/ncvs/src/usr.sbin/arp/arp.8,v
retrieving revision 1.8.2.11
diff -u -r1.8.2.11 arp.8
--- usr.sbin/arp/arp.8	11 Mar 2003 21:13:48 -0000	1.8.2.11
+++ usr.sbin/arp/arp.8	6 Jul 2003 14:23:14 -0000
@@ -41,9 +41,11 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl n
+.Op Fl i Ar ifname
 .Ar hostname
 .Nm
 .Op Fl n
+.Op Fl i Ar ifname
 .Fl a
 .Nm
 .Fl d Ar hostname
@@ -99,6 +101,11 @@
 flag may be combined with the
 .Fl a
 flag to delete all entries.
+.It Fl i Ar ifname
+Restrict searching for
+.Tn ARP
+entries to single interface
+.Ar ifname .
 .It Fl n
 Show network addresses as numbers (normally
 .Nm
Index: usr.sbin/arp/arp.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/arp/arp.c,v
retrieving revision 1.22.2.12
diff -u -r1.22.2.12 arp.c
--- usr.sbin/arp/arp.c	16 Apr 2003 10:02:37 -0000	1.22.2.12
+++ usr.sbin/arp/arp.c	6 Jul 2003 14:23:14 -0000
@@ -103,6 +103,7 @@
 static int nflag;	/* no reverse dns lookups */
 static int aflag;	/* do it for all entries */
 static int s = -1;
+static char *rifname = NULL;
 
 struct	sockaddr_in so_mask;
 struct	sockaddr_inarp blank_sin, sin_m;
@@ -131,7 +132,7 @@
 	int rtn = 0;
 
 	pid = getpid();
-	while ((ch = getopt(argc, argv, "andfsS")) != -1)
+	while ((ch = getopt(argc, argv, "andfsSi:")) != -1)
 		switch((char)ch) {
 		case 'a':
 			aflag = 1;
@@ -151,6 +152,10 @@
 		case 'f' :
 			SETFUNC(F_FILESET);
 			break;
+		case 'i':
+			if ((rifname = optarg) == NULL)
+				errx(1, "out of memory");
+			break;
 		case '?':
 		default:
 			usage();
@@ -170,6 +175,8 @@
 
 	if (!func)
 		func = F_GET;
+	if (rifname && func != F_GET)
+		errx(1, "-i not applicable to non-read functions");
 	switch (func) {
 	case F_GET:
 		if (aflag) {
@@ -375,8 +382,11 @@
 	}
 	search(addr->sin_addr.s_addr, print_entry);
 	if (found_entry == 0) {
-		printf("%s (%s) -- no entry\n",
+		printf("%s (%s) -- no entry",
 		    host, inet_ntoa(addr->sin_addr));
+		if (rifname)
+			printf(" at %s", rifname);
+		printf("\n");
 		return(1);
 	}
 	return(0);
@@ -458,6 +468,7 @@
 	struct rt_msghdr *rtm;
 	struct sockaddr_inarp *sin2;
 	struct sockaddr_dl *sdl;
+	char ifname[IF_NAMESIZE];
 
 	mib[0] = CTL_NET;
 	mib[1] = PF_ROUTE;
@@ -476,6 +487,9 @@
 		rtm = (struct rt_msghdr *)next;
 		sin2 = (struct sockaddr_inarp *)(rtm + 1);
 		(char *)sdl = (char *)sin2 + ROUNDUP(sin2->sin_len);
+		if (rifname && if_indextoname(sdl->sdl_index, ifname) != NULL &&
+		    strcmp(ifname, rifname))
+			continue;
 		if (addr) {
 			if (addr != sin2->sin_addr.s_addr)
 				continue;
@@ -585,8 +599,8 @@
 usage(void)
 {
 	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
-		"usage: arp [-n] hostname",
-		"       arp [-n] -a",
+		"usage: arp [-n] [-i ifname] hostname",
+		"       arp [-n] [-i ifname] -a",
 		"       arp -d hostname [pub]",
 		"       arp -d -a",
 		"       arp -s hostname ether_addr [temp] [pub]",



*** PATCH 2


--- arp.c.iflag	Sun Jul  6 18:23:31 2003
+++ arp.c	Sun Jul  6 20:01:18 2003
@@ -98,6 +98,8 @@
 int my_ether_aton(char *a, struct ether_addr *n);
 int rtmsg(int cmd);
 int get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr);
+char **getifnlist(void);
+int checkifname(char *ifname);
 
 static int pid;
 static int nflag;	/* no reverse dns lookups */
@@ -155,6 +157,8 @@
 		case 'i':
 			if ((rifname = optarg) == NULL)
 				errx(1, "out of memory");
+			if (checkifname(rifname) == 0)
+				errx(1, "no such interface: %s", rifname);
 			break;
 		case '?':
 		default:
@@ -216,6 +220,81 @@
 	}
 
 	return(rtn);
+}
+
+/*
+ * Get interface list
+ */
+#define	MIBSZ	6
+
+char **getifnlist(void)
+{
+	size_t	needed;
+	int	ifcount;
+	int	mib[MIBSZ];
+	char	*buf, *lim, *next;
+	struct	if_msghdr *ifm, *nextifm;
+	struct	sockaddr_dl *sdl;
+	char	*name, **ifnlist;
+
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_INET;	/* address family */
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = 0;
+
+	if (sysctl(mib, MIBSZ, NULL, &needed, NULL, 0) < 0)
+		errx(1, "iflist-sysctl-estimate");
+	if ((buf = malloc(needed)) == NULL)
+		errx(1, "malloc");
+	if (sysctl(mib, MIBSZ, buf, &needed, NULL, 0) < 0)
+		errx(1, "actual retrieval of interface table");
+	lim = buf + needed;
+
+	ifcount = 1;	/* reserve space for trailing NULL */
+	ifnlist = NULL;
+	next = buf;
+	while (next < lim) {
+		ifm = (struct if_msghdr *)next;
+		
+		if (ifm->ifm_type == RTM_IFINFO)
+			sdl = (struct sockaddr_dl *)(ifm + 1);
+		else
+			errx(1, "out of sync parsing NET_RT_IFLIST");
+
+		next += ifm->ifm_msglen;
+		while (next < lim) {
+			nextifm = (struct if_msghdr *)next;
+
+			if (nextifm->ifm_type != RTM_NEWADDR)
+				break;
+
+			next += nextifm->ifm_msglen;
+		}
+		name = malloc(sdl->sdl_nlen + 1);
+		if (name == NULL)
+			errx(1, "malloc");
+		strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
+		name[sdl->sdl_nlen] = '\0';
+		ifnlist = realloc(ifnlist, ifcount*sizeof(char *));
+		if (ifnlist == NULL)
+			errx(1, "malloc");
+		ifnlist[ifcount-1] = name;
+		ifnlist[ifcount] = NULL;
+		ifcount++;
+	}
+	return ifnlist;
+}
+
+int checkifname(char *ifname)
+{
+	char **ifl, *p;
+	ifl = getifnlist();
+	while ((p = *ifl++) != NULL)
+		if (strcmp(p, ifname) == 0)
+			return 1;
+	return 0;
 }
 
 /*
>Release-Note:
>Audit-Trail:

From: Dmitry Morozovsky <marck@rinet.ru>
To: freebsd-gnats-submit@freebsd.org
Cc:  
Subject: Re: bin/54151 patch correction
Date: Mon, 7 Jul 2003 21:40:33 +0400 (MSD)

 From discussion at -net@:
 
 DL> The first patch looks ok except for the text of the error message at
 DL> source line 157.
 
 Well, it's a piece of old junk: firstly, I used strdup(), and then realized it
 isn't necessary for argv. So, these lines possibly should look simply like
 
 @@ -151,6 +154,11 @@
                 case 'f' :
                         SETFUNC(F_FILESET);
                         break;
 +               case 'i':
 +                       rifname = optarg;
 +                       if (checkifname(rifname) == 0)
 +                               errx(1, "no such interface: %s", rifname);
 +                       break;
                 case '?':
                 default:
                         usage();

From: Yar Tikhiy <yar@FreeBSD.org>
To: freebsd-gnats-submit@FreeBSD.org, marck@rinet.ru
Cc:  
Subject: Re: bin/54151: [PATCH] -i (restrict to one interface) patch from arp(8)
Date: Thu, 17 Jul 2003 17:35:56 +0400

 The feature you've proposed looks really juicy to me so long as
 there's a router between numerous VLANs under my management, too.
 I've introduced some changes into your patch to improve its style
 and language.  One of my points is using if_nametoindex(3) to check
 if an interface does exist, instead of all that code around sysctl(2).
 Could you please confirm my version of the patch works for you?
 
 -- 
 Yar
 
 Index: arp.8
 ===================================================================
 RCS file: /home/ncvs/src/usr.sbin/arp/arp.8,v
 retrieving revision 1.20
 diff -u -p -r1.20 arp.8
 --- arp.8	27 Dec 2002 10:09:04 -0000	1.20
 +++ arp.8	17 Jul 2003 13:30:20 -0000
 @@ -41,9 +41,11 @@
  .Sh SYNOPSIS
  .Nm
  .Op Fl n
 +.Op Fl i Ar interface
  .Ar hostname
  .Nm
  .Op Fl n
 +.Op Fl i Ar interface
  .Fl a
  .Nm
  .Fl d Ar hostname
 @@ -99,6 +101,12 @@ Alternatively, the
  flag may be combined with the
  .Fl a
  flag to delete all entries.
 +.It Fl i Ar interface
 +Limit the operation scope to the
 +.Tn ARP
 +entries on
 +.Ar interface .
 +Applicable to the display operations only.
  .It Fl n
  Show network addresses as numbers (normally
  .Nm
 Index: arp.c
 ===================================================================
 RCS file: /home/ncvs/src/usr.sbin/arp/arp.c,v
 retrieving revision 1.45
 diff -u -p -r1.45 arp.c
 --- arp.c	3 May 2003 21:06:35 -0000	1.45
 +++ arp.c	17 Jul 2003 13:30:20 -0000
 @@ -104,6 +104,7 @@ static pid_t pid;
  static int nflag;	/* no reverse dns lookups */
  static int aflag;	/* do it for all entries */
  static int s = -1;
 +static char *rifname;
  
  struct	sockaddr_in so_mask;
  struct	sockaddr_inarp blank_sin, sin_m;
 @@ -132,7 +133,7 @@ main(int argc, char *argv[])
  	int rtn = 0;
  
  	pid = getpid();
 -	while ((ch = getopt(argc, argv, "andfsS")) != -1)
 +	while ((ch = getopt(argc, argv, "andfsSi:")) != -1)
  		switch((char)ch) {
  		case 'a':
  			aflag = 1;
 @@ -152,6 +153,9 @@ main(int argc, char *argv[])
  		case 'f' :
  			SETFUNC(F_FILESET);
  			break;
 +		case 'i':
 +			rifname = optarg;
 +			break;
  		case '?':
  		default:
  			usage();
 @@ -171,6 +175,16 @@ main(int argc, char *argv[])
  
  	if (!func)
  		func = F_GET;
 +	if (rifname) {
 +		if (func != F_GET)
 +			errx(1, "-i not applicable to this operation");
 +		if (if_nametoindex(rifname) == 0) {
 +			if (errno == ENXIO)
 +				errx(1, "interface %s does not exist", rifname);
 +			else
 +				err(1, "if_nametoindex(%s)", rifname);
 +		}
 +	}
  	switch (func) {
  	case F_GET:
  		if (aflag) {
 @@ -376,8 +390,11 @@ get(char *host)
  	}
  	search(addr->sin_addr.s_addr, print_entry);
  	if (found_entry == 0) {
 -		printf("%s (%s) -- no entry\n",
 +		printf("%s (%s) -- no entry",
  		    host, inet_ntoa(addr->sin_addr));
 +		if (rifname)
 +			printf(" on %s", rifname);
 +		printf("\n");
  		return(1);
  	}
  	return(0);
 @@ -459,6 +476,7 @@ search(u_long addr, void (*action)(struc
  	struct rt_msghdr *rtm;
  	struct sockaddr_inarp *sin2;
  	struct sockaddr_dl *sdl;
 +	char ifname[IFNAMSIZ];
  
  	mib[0] = CTL_NET;
  	mib[1] = PF_ROUTE;
 @@ -477,6 +495,9 @@ search(u_long addr, void (*action)(struc
  		rtm = (struct rt_msghdr *)next;
  		sin2 = (struct sockaddr_inarp *)(rtm + 1);
  		(char *)sdl = (char *)sin2 + ROUNDUP(sin2->sin_len);
 +		if (rifname && if_indextoname(sdl->sdl_index, ifname) != NULL &&
 +		    strcmp(ifname, rifname))
 +			continue;
  		if (addr) {
  			if (addr != sin2->sin_addr.s_addr)
  				continue;
 @@ -593,8 +614,8 @@ void
  usage(void)
  {
  	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
 -		"usage: arp [-n] hostname",
 -		"       arp [-n] -a",
 +		"usage: arp [-n] [-i ifname] hostname",
 +		"       arp [-n] [-i ifname] -a",
  		"       arp -d hostname [pub]",
  		"       arp -d -a",
  		"       arp -s hostname ether_addr [temp] [pub]",
State-Changed-From-To: open->analyzed 
State-Changed-By: yar 
State-Changed-When: Thu Jul 17 07:34:01 PDT 2003 
State-Changed-Why:  
The feature proposed looks good, yet implementation details 
need to be settled. 


Responsible-Changed-From-To: freebsd-bugs->yar 
Responsible-Changed-By: yar 
Responsible-Changed-When: Thu Jul 17 07:34:01 PDT 2003 
Responsible-Changed-Why:  
I'll take it since I represent an interested party. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=54151 

From: Dmitry Morozovsky <marck@rinet.ru>
To: Yar Tikhiy <yar@FreeBSD.org>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/54151: [PATCH] -i (restrict to one interface) patch from
 arp(8)
Date: Fri, 18 Jul 2003 02:38:21 +0400 (MSD)

 On Thu, 17 Jul 2003, Yar Tikhiy wrote:
 
 YT> The feature you've proposed looks really juicy to me so long as
 YT> there's a router between numerous VLANs under my management, too.
 YT> I've introduced some changes into your patch to improve its style
 YT> and language.  One of my points is using if_nametoindex(3) to check
 YT> if an interface does exist, instead of all that code around sysctl(2).
 YT> Could you please confirm my version of the patch works for you?
 
 Surely it does work. Thanks for cleaning up after me, as I seem to totally
 overlook if_nametoindex() while successfully found if_indextoname()! ;-)
 
 
 Sincerely,
 D.Marck                                     [DM5020, MCK-RIPE, DM3-RIPN]
 ------------------------------------------------------------------------
 *** Dmitry Morozovsky --- D.Marck --- Wild Woozle --- marck@rinet.ru ***
 ------------------------------------------------------------------------
State-Changed-From-To: analyzed->patched 
State-Changed-By: yar 
State-Changed-When: Mon Jul 21 08:57:45 PDT 2003 
State-Changed-Why:  
The feature proposed has appeared in CURRENT and will 
be MFC'ed after a fortnight of testing it.  Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=54151 
State-Changed-From-To: patched->closed 
State-Changed-By: yar 
State-Changed-When: Fri Aug 1 06:30:46 PDT 2003 
State-Changed-Why:  
Merged to STABLE as well.  Thanks for your contribution! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=54151 
>Unformatted:
