Module Name:    src
Committed By:   christos
Date:           Fri Jul  6 00:50:05 UTC 2018

Modified Files:
        src/usr.sbin/arp: arp.8 arp.c

Log Message:
Add an "auto" keyword to auto-determine the link address from the inet addr.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/usr.sbin/arp/arp.8
cvs rdiff -u -r1.59 -r1.60 src/usr.sbin/arp/arp.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/arp/arp.8
diff -u src/usr.sbin/arp/arp.8:1.23 src/usr.sbin/arp/arp.8:1.24
--- src/usr.sbin/arp/arp.8:1.23	Mon Jul  8 00:31:12 2013
+++ src/usr.sbin/arp/arp.8	Thu Jul  5 20:50:05 2018
@@ -1,4 +1,4 @@
-.\"	$NetBSD: arp.8,v 1.23 2013/07/08 04:31:12 apb Exp $
+.\"	$NetBSD: arp.8,v 1.24 2018/07/06 00:50:05 christos Exp $
 .\"
 .\" Copyright (c) 1985, 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -29,7 +29,7 @@
 .\"
 .\"	from: @(#)arp.8	8.2 (Berkeley) 4/27/95
 .\"
-.Dd July 8, 2013
+.Dd July 5, 2018
 .Dt ARP 8
 .Os
 .Sh NAME
@@ -132,11 +132,19 @@ server,
 responding to requests for
 .Ar hostname
 even though the host address is not its own.
+.Pp
 If the word
 .Cm proxy
 is also given, the published entry will be a
 .Dq proxy only
 entry.
+In this case the
+.Ar ether_addr
+can be given as
+.Cm auto
+in which case the interfaces on this host will be examined,
+and if one of them is found to occupy the same subnet, its
+Ethernet address will be used.
 .It Fl v
 Display verbose information when adding or deleting
 .Tn ARP

Index: src/usr.sbin/arp/arp.c
diff -u src/usr.sbin/arp/arp.c:1.59 src/usr.sbin/arp/arp.c:1.60
--- src/usr.sbin/arp/arp.c:1.59	Fri Jun  8 00:24:12 2018
+++ src/usr.sbin/arp/arp.c	Thu Jul  5 20:50:05 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: arp.c,v 1.59 2018/06/08 04:24:12 nonaka Exp $ */
+/*	$NetBSD: arp.c,v 1.60 2018/07/06 00:50:05 christos Exp $ */
 
 /*
  * Copyright (c) 1984, 1993
@@ -42,7 +42,7 @@ __COPYRIGHT("@(#) Copyright (c) 1984, 19
 #if 0
 static char sccsid[] = "@(#)arp.c	8.3 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: arp.c,v 1.59 2018/06/08 04:24:12 nonaka Exp $");
+__RCSID("$NetBSD: arp.c,v 1.60 2018/07/06 00:50:05 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -84,14 +84,14 @@ static void dump(uint32_t);
 static void delete(const char *, const char *);
 static void sdl_print(const struct sockaddr_dl *);
 static int getifname(u_int16_t, char *, size_t);
-static int atosdl(const char *s, struct sockaddr_dl *sdl);
+static int atosdl(const char *, struct sockaddr_dl *);
 static int file(const char *);
 static void get(const char *);
 static int getinetaddr(const char *, struct in_addr *);
 static int getsocket(void);
-static struct rt_msghdr *
-	rtmsg(const int, const int,  struct rt_msghdr *,
-	    const struct sockaddr_inarp *, const struct sockaddr_dl *);
+static int getetheraddr(struct in_addr, struct sockaddr_dl *);
+static struct rt_msghdr * rtmsg(const int, const int,  struct rt_msghdr *,
+	const struct sockaddr_inarp *, const struct sockaddr_dl *);
 static int set(int, char **);
 static void usage(void) __dead;
 
@@ -278,7 +278,7 @@ set(int argc, char **argv)
 
 	if (getinetaddr(host, &sin_m.sin_addr) == -1)
 		return (1);
-	if (atosdl(eaddr, &sdl_m))
+	if (!strcmp(eaddr, "auto") && atosdl(eaddr, &sdl_m))
 		warnx("invalid link-level address '%s'", eaddr);
 	doing_proxy = flags = export_only = expire_time = 0;
 	for (; argc-- > 0; argv++) {
@@ -309,6 +309,10 @@ set(int argc, char **argv)
 		}
 
 	}
+	if (doing_proxy && !strcmp(eaddr, "auto")) {
+		if (getetheraddr(sin_m.sin_addr, &sdl_m) == -1)
+			return 1;
+	}
 tryagain:
 	rtm = rtmsg(s, RTM_GET, NULL, &sin_m, &sdl_m);
 	if (rtm == NULL) {
@@ -706,7 +710,7 @@ getifname(u_int16_t ifindex, char *ifnam
 {
 	int i;
 	struct ifaddrs *addr;
-	const struct sockaddr_dl *sdl = NULL;
+	const struct sockaddr_dl *sdl;
 	static struct ifaddrs* ifaddrs = NULL;
 
 	if (ifaddrs == NULL) {
@@ -729,3 +733,51 @@ getifname(u_int16_t ifindex, char *ifnam
 
 	return -1;
 }
+
+static int
+getetheraddr(struct in_addr ipaddr, struct sockaddr_dl *sdl)
+{
+	struct ifaddrs *ifaddrs, *addr;
+	in_addr_t ina, mask;
+	char ifname[IFNAMSIZ];
+
+	if (getifaddrs(&ifaddrs) != 0) {
+		warn("getifaddrs");
+		return -1;
+	}
+
+	for (addr = ifaddrs; addr; addr = addr->ifa_next) {
+		if (addr->ifa_addr == NULL ||
+		    addr->ifa_addr->sa_family != AF_INET)
+			continue;
+		if ((addr->ifa_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
+		    IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST))
+			continue;
+
+		mask = ((struct sockaddr_in *)(void *)addr->ifa_netmask)->sin_addr.s_addr;
+		ina = ((struct sockaddr_in *)(void *)addr->ifa_addr)->sin_addr.s_addr;
+		if ((ipaddr.s_addr & mask) != (ina & mask))
+			continue;
+		strlcpy(ifname, addr->ifa_name, sizeof(ifname));
+		break;
+	}
+	if (addr == NULL) {
+		warnx("No interface matched %s", inet_ntoa(ipaddr));
+		freeifaddrs(ifaddrs);
+		return -1;
+	}
+
+	for (addr = ifaddrs; addr; addr = addr->ifa_next) {
+		if (addr->ifa_addr == NULL ||
+		    addr->ifa_addr->sa_family != AF_LINK)
+			continue;
+		if (strcmp(ifname, addr->ifa_name) != 0)
+			continue;
+		memcpy(sdl, addr->ifa_addr, sizeof(*sdl));
+		freeifaddrs(ifaddrs);
+		return 0;
+	}
+	warnx("No link address for interface %s", ifname);
+	freeifaddrs(ifaddrs);
+	return -1;
+}

Reply via email to