xref: /freebsd/usr.sbin/arp/arp.c (revision 0442747236f4a934d1fc6a3354ce691b4b97067a)
1dea673e9SRodney W. Grimes /*
2dea673e9SRodney W. Grimes  * Copyright (c) 1984, 1993
3dea673e9SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4dea673e9SRodney W. Grimes  *
5dea673e9SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
6dea673e9SRodney W. Grimes  * Sun Microsystems, Inc.
7dea673e9SRodney W. Grimes  *
8dea673e9SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
9dea673e9SRodney W. Grimes  * modification, are permitted provided that the following conditions
10dea673e9SRodney W. Grimes  * are met:
11dea673e9SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
12dea673e9SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
13dea673e9SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
14dea673e9SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
15dea673e9SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
16dea673e9SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
17dea673e9SRodney W. Grimes  *    must display the following acknowledgement:
18dea673e9SRodney W. Grimes  *	This product includes software developed by the University of
19dea673e9SRodney W. Grimes  *	California, Berkeley and its contributors.
20dea673e9SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
21dea673e9SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
22dea673e9SRodney W. Grimes  *    without specific prior written permission.
23dea673e9SRodney W. Grimes  *
24dea673e9SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25dea673e9SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26dea673e9SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27dea673e9SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28dea673e9SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29dea673e9SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30dea673e9SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31dea673e9SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32dea673e9SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33dea673e9SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34dea673e9SRodney W. Grimes  * SUCH DAMAGE.
35dea673e9SRodney W. Grimes  */
36dea673e9SRodney W. Grimes 
37dea673e9SRodney W. Grimes #ifndef lint
38a42a667dSPoul-Henning Kamp static char const copyright[] =
39dea673e9SRodney W. Grimes "@(#) Copyright (c) 1984, 1993\n\
40dea673e9SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
41dea673e9SRodney W. Grimes #endif /* not lint */
42dea673e9SRodney W. Grimes 
43dea673e9SRodney W. Grimes #ifndef lint
44c72049e4SPhilippe Charnier #if 0
45a42a667dSPoul-Henning Kamp static char const sccsid[] = "@(#)from: arp.c	8.2 (Berkeley) 1/2/94";
46c72049e4SPhilippe Charnier #endif
47c72049e4SPhilippe Charnier static const char rcsid[] =
4897d92980SPeter Wemm   "$FreeBSD$";
49dea673e9SRodney W. Grimes #endif /* not lint */
50dea673e9SRodney W. Grimes 
51dea673e9SRodney W. Grimes /*
52dea673e9SRodney W. Grimes  * arp - display, set, and delete arp table entries
53dea673e9SRodney W. Grimes  */
54dea673e9SRodney W. Grimes 
55dea673e9SRodney W. Grimes 
56dea673e9SRodney W. Grimes #include <sys/param.h>
57dea673e9SRodney W. Grimes #include <sys/file.h>
58dea673e9SRodney W. Grimes #include <sys/socket.h>
59a42a667dSPoul-Henning Kamp #include <sys/sockio.h>
60dea673e9SRodney W. Grimes #include <sys/sysctl.h>
61a42a667dSPoul-Henning Kamp #include <sys/ioctl.h>
62628d2ac1SGarrett Wollman #include <sys/time.h>
63dea673e9SRodney W. Grimes 
64dea673e9SRodney W. Grimes #include <net/if.h>
65dea673e9SRodney W. Grimes #include <net/if_dl.h>
66dea673e9SRodney W. Grimes #include <net/if_types.h>
67dea673e9SRodney W. Grimes #include <net/route.h>
68dea673e9SRodney W. Grimes 
69dea673e9SRodney W. Grimes #include <netinet/in.h>
70dea673e9SRodney W. Grimes #include <netinet/if_ether.h>
71dea673e9SRodney W. Grimes 
72dea673e9SRodney W. Grimes #include <arpa/inet.h>
73dea673e9SRodney W. Grimes 
74c72049e4SPhilippe Charnier #include <err.h>
75dea673e9SRodney W. Grimes #include <errno.h>
76c72049e4SPhilippe Charnier #include <netdb.h>
77dea673e9SRodney W. Grimes #include <nlist.h>
78c72049e4SPhilippe Charnier #include <paths.h>
79dea673e9SRodney W. Grimes #include <stdio.h>
80a42a667dSPoul-Henning Kamp #include <stdlib.h>
81a42a667dSPoul-Henning Kamp #include <strings.h>
82c72049e4SPhilippe Charnier #include <unistd.h>
83dea673e9SRodney W. Grimes 
848dc4b495SJulian Elischer void search(u_long addr, void (*action)(struct sockaddr_dl *sdl,
858dc4b495SJulian Elischer 	struct sockaddr_inarp *sin, struct rt_msghdr *rtm));
868dc4b495SJulian Elischer void print_entry(struct sockaddr_dl *sdl,
878dc4b495SJulian Elischer 	struct sockaddr_inarp *sin, struct rt_msghdr *rtm);
888dc4b495SJulian Elischer void nuke_entry(struct sockaddr_dl *sdl,
898dc4b495SJulian Elischer 	struct sockaddr_inarp *sin, struct rt_msghdr *rtm);
90a42a667dSPoul-Henning Kamp int delete(char *host, char *info);
91a42a667dSPoul-Henning Kamp void ether_print(u_char *cp);
92a42a667dSPoul-Henning Kamp void usage(void);
93a42a667dSPoul-Henning Kamp int set(int argc, char **argv);
948dc4b495SJulian Elischer int get(char *host);
95a42a667dSPoul-Henning Kamp int file(char *name);
96a42a667dSPoul-Henning Kamp void getsocket(void);
9763c64400SNate Williams int my_ether_aton(char *a, u_char *n);
98a42a667dSPoul-Henning Kamp int rtmsg(int cmd);
991fece1a6SYoshinobu Inoue int get_ether_addr(u_int32_t ipaddr, u_char *hwaddr);
100a42a667dSPoul-Henning Kamp 
101dea673e9SRodney W. Grimes static int pid;
1028dc4b495SJulian Elischer static int nflag;	/* no reverse dns lookups */
1038dc4b495SJulian Elischer static int aflag;	/* do it for all entries */
104dea673e9SRodney W. Grimes static int s = -1;
105dea673e9SRodney W. Grimes 
1068dc4b495SJulian Elischer /* which function we're supposed to do */
1078dc4b495SJulian Elischer #define F_GET		1
1088dc4b495SJulian Elischer #define F_SET		2
1098dc4b495SJulian Elischer #define F_FILESET	3
1108dc4b495SJulian Elischer #define F_REPLACE	4
1118dc4b495SJulian Elischer #define F_DELETE	5
1128dc4b495SJulian Elischer 
1133a6a5ebeSRuslan Ermilov #define ROUNDUP(a) \
1143a6a5ebeSRuslan Ermilov 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1158dc4b495SJulian Elischer #define SETFUNC(f)	{ if (func) usage(); func = (f); }
1168dc4b495SJulian Elischer 
117a42a667dSPoul-Henning Kamp int
1183f844a22SRuslan Ermilov main(int argc, char *argv[])
119dea673e9SRodney W. Grimes {
1208dc4b495SJulian Elischer 	int ch, func = 0;
1218dc4b495SJulian Elischer 	int rtn = 0;
122dea673e9SRodney W. Grimes 
123dea673e9SRodney W. Grimes 	pid = getpid();
1246c3f552aSWarner Losh 	while ((ch = getopt(argc, argv, "andfsS")) != -1)
125dea673e9SRodney W. Grimes 		switch((char)ch) {
126dea673e9SRodney W. Grimes 		case 'a':
1278dc4b495SJulian Elischer 			aflag = 1;
1288dc4b495SJulian Elischer 			break;
129dea673e9SRodney W. Grimes 		case 'd':
1308dc4b495SJulian Elischer 			SETFUNC(F_DELETE);
1318dc4b495SJulian Elischer 			break;
132dea673e9SRodney W. Grimes 		case 'n':
133dea673e9SRodney W. Grimes 			nflag = 1;
1348dc4b495SJulian Elischer 			break;
135a42a667dSPoul-Henning Kamp 		case 'S':
1368dc4b495SJulian Elischer 			SETFUNC(F_REPLACE);
1378dc4b495SJulian Elischer 			break;
138dea673e9SRodney W. Grimes 		case 's':
1398dc4b495SJulian Elischer 			SETFUNC(F_SET);
1408dc4b495SJulian Elischer 			break;
14195319e17SJordan K. Hubbard 		case 'f' :
1428dc4b495SJulian Elischer 			SETFUNC(F_FILESET);
1438dc4b495SJulian Elischer 			break;
144dea673e9SRodney W. Grimes 		case '?':
145dea673e9SRodney W. Grimes 		default:
146dea673e9SRodney W. Grimes 			usage();
147dea673e9SRodney W. Grimes 		}
1488dc4b495SJulian Elischer 	argc -= optind;
1498dc4b495SJulian Elischer 	argv += optind;
1508dc4b495SJulian Elischer 
1518dc4b495SJulian Elischer 	if (!func)
1528dc4b495SJulian Elischer 		func = F_GET;
1538dc4b495SJulian Elischer 	switch (func) {
1548dc4b495SJulian Elischer 	case F_GET:
1558dc4b495SJulian Elischer 		if (aflag) {
1568dc4b495SJulian Elischer 			if (argc != 0)
157dea673e9SRodney W. Grimes 				usage();
1588dc4b495SJulian Elischer 			search(0, print_entry);
1598dc4b495SJulian Elischer 		} else {
1608dc4b495SJulian Elischer 			if (argc != 1)
1618dc4b495SJulian Elischer 				usage();
1628dc4b495SJulian Elischer 			get(argv[0]);
1638dc4b495SJulian Elischer 		}
1648dc4b495SJulian Elischer 		break;
1658dc4b495SJulian Elischer 	case F_SET:
1668dc4b495SJulian Elischer 	case F_REPLACE:
1673f844a22SRuslan Ermilov 		if (argc < 2 || argc > 6)
1688dc4b495SJulian Elischer 			usage();
1698dc4b495SJulian Elischer 		if (func == F_REPLACE)
1708dc4b495SJulian Elischer 			(void) delete(argv[0], NULL);
1718dc4b495SJulian Elischer 		rtn = set(argc, argv) ? 1 : 0;
1728dc4b495SJulian Elischer 		break;
1738dc4b495SJulian Elischer 	case F_DELETE:
1748dc4b495SJulian Elischer 		if (aflag) {
1758dc4b495SJulian Elischer 			if (argc != 0)
1768dc4b495SJulian Elischer 				usage();
1778dc4b495SJulian Elischer 			search(0, nuke_entry);
1788dc4b495SJulian Elischer 		} else {
1798dc4b495SJulian Elischer 			if (argc < 1 || argc > 2)
1808dc4b495SJulian Elischer 				usage();
1818dc4b495SJulian Elischer 			rtn = delete(argv[0], argv[1]);
1828dc4b495SJulian Elischer 		}
1838dc4b495SJulian Elischer 		break;
1848dc4b495SJulian Elischer 	case F_FILESET:
1858dc4b495SJulian Elischer 		if (argc != 1)
1868dc4b495SJulian Elischer 			usage();
1878dc4b495SJulian Elischer 		rtn = file(argv[0]);
1888dc4b495SJulian Elischer 		break;
1898dc4b495SJulian Elischer 	}
1908dc4b495SJulian Elischer 
1918dc4b495SJulian Elischer 	return(rtn);
192dea673e9SRodney W. Grimes }
193dea673e9SRodney W. Grimes 
194dea673e9SRodney W. Grimes /*
195dea673e9SRodney W. Grimes  * Process a file to set standard arp entries
196dea673e9SRodney W. Grimes  */
197a42a667dSPoul-Henning Kamp int
198a42a667dSPoul-Henning Kamp file(char *name)
199dea673e9SRodney W. Grimes {
200dea673e9SRodney W. Grimes 	FILE *fp;
201dea673e9SRodney W. Grimes 	int i, retval;
202dea673e9SRodney W. Grimes 	char line[100], arg[5][50], *args[5];
203dea673e9SRodney W. Grimes 
204c72049e4SPhilippe Charnier 	if ((fp = fopen(name, "r")) == NULL)
205c72049e4SPhilippe Charnier 		errx(1, "cannot open %s", name);
206dea673e9SRodney W. Grimes 	args[0] = &arg[0][0];
207dea673e9SRodney W. Grimes 	args[1] = &arg[1][0];
208dea673e9SRodney W. Grimes 	args[2] = &arg[2][0];
209dea673e9SRodney W. Grimes 	args[3] = &arg[3][0];
210dea673e9SRodney W. Grimes 	args[4] = &arg[4][0];
211dea673e9SRodney W. Grimes 	retval = 0;
212dea673e9SRodney W. Grimes 	while(fgets(line, 100, fp) != NULL) {
2130cecd500SKris Kennaway 		i = sscanf(line, "%49s %49s %49s %49s %49s", arg[0], arg[1],
214135adb1eSJordan K. Hubbard 		    arg[2], arg[3], arg[4]);
215dea673e9SRodney W. Grimes 		if (i < 2) {
216c72049e4SPhilippe Charnier 			warnx("bad line: %s", line);
217dea673e9SRodney W. Grimes 			retval = 1;
218dea673e9SRodney W. Grimes 			continue;
219dea673e9SRodney W. Grimes 		}
220dea673e9SRodney W. Grimes 		if (set(i, args))
221dea673e9SRodney W. Grimes 			retval = 1;
222dea673e9SRodney W. Grimes 	}
223dea673e9SRodney W. Grimes 	fclose(fp);
224dea673e9SRodney W. Grimes 	return (retval);
225dea673e9SRodney W. Grimes }
226dea673e9SRodney W. Grimes 
227a42a667dSPoul-Henning Kamp void
228a42a667dSPoul-Henning Kamp getsocket(void)
229a42a667dSPoul-Henning Kamp {
230dea673e9SRodney W. Grimes 	if (s < 0) {
231dea673e9SRodney W. Grimes 		s = socket(PF_ROUTE, SOCK_RAW, 0);
232c72049e4SPhilippe Charnier 		if (s < 0)
233c72049e4SPhilippe Charnier 			err(1, "socket");
234dea673e9SRodney W. Grimes 	}
235dea673e9SRodney W. Grimes }
236dea673e9SRodney W. Grimes 
237dea673e9SRodney W. Grimes struct	sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
238dea673e9SRodney W. Grimes struct	sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m;
239dea673e9SRodney W. Grimes struct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
2403f844a22SRuslan Ermilov int	expire_time, flags, doing_proxy, proxy_only, found_entry;
241dea673e9SRodney W. Grimes struct	{
242dea673e9SRodney W. Grimes 	struct	rt_msghdr m_rtm;
243dea673e9SRodney W. Grimes 	char	m_space[512];
244dea673e9SRodney W. Grimes }	m_rtmsg;
245dea673e9SRodney W. Grimes 
246dea673e9SRodney W. Grimes /*
247dea673e9SRodney W. Grimes  * Set an individual arp entry
248dea673e9SRodney W. Grimes  */
249a42a667dSPoul-Henning Kamp int
250a42a667dSPoul-Henning Kamp set(int argc, char **argv)
251dea673e9SRodney W. Grimes {
252dea673e9SRodney W. Grimes 	struct hostent *hp;
253dea673e9SRodney W. Grimes 	register struct sockaddr_inarp *sin = &sin_m;
254dea673e9SRodney W. Grimes 	register struct sockaddr_dl *sdl;
255dea673e9SRodney W. Grimes 	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
256dea673e9SRodney W. Grimes 	u_char *ea;
257dea673e9SRodney W. Grimes 	char *host = argv[0], *eaddr = argv[1];
258dea673e9SRodney W. Grimes 
259dea673e9SRodney W. Grimes 	getsocket();
260dea673e9SRodney W. Grimes 	argc -= 2;
261dea673e9SRodney W. Grimes 	argv += 2;
262dea673e9SRodney W. Grimes 	sdl_m = blank_sdl;
263dea673e9SRodney W. Grimes 	sin_m = blank_sin;
264dea673e9SRodney W. Grimes 	sin->sin_addr.s_addr = inet_addr(host);
2653f844a22SRuslan Ermilov 	if (sin->sin_addr.s_addr == INADDR_NONE) {
266dea673e9SRodney W. Grimes 		if (!(hp = gethostbyname(host))) {
267c72049e4SPhilippe Charnier 			warnx("%s: %s", host, hstrerror(h_errno));
268dea673e9SRodney W. Grimes 			return (1);
269dea673e9SRodney W. Grimes 		}
270dea673e9SRodney W. Grimes 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
271dea673e9SRodney W. Grimes 		    sizeof sin->sin_addr);
272dea673e9SRodney W. Grimes 	}
2733f844a22SRuslan Ermilov 	doing_proxy = flags = proxy_only = expire_time = 0;
274dea673e9SRodney W. Grimes 	while (argc-- > 0) {
275dea673e9SRodney W. Grimes 		if (strncmp(argv[0], "temp", 4) == 0) {
2763f844a22SRuslan Ermilov 			struct timeval tv;
2773f844a22SRuslan Ermilov 			gettimeofday(&tv, 0);
2783f844a22SRuslan Ermilov 			expire_time = tv.tv_sec + 20 * 60;
279dea673e9SRodney W. Grimes 		}
280dea673e9SRodney W. Grimes 		else if (strncmp(argv[0], "pub", 3) == 0) {
281dea673e9SRodney W. Grimes 			flags |= RTF_ANNOUNCE;
2823f844a22SRuslan Ermilov 			doing_proxy = 1;
2833f844a22SRuslan Ermilov 			if (argc && strncmp(argv[1], "only", 3) == 0) {
2843f844a22SRuslan Ermilov 				proxy_only = 1;
2853f844a22SRuslan Ermilov 				sin_m.sin_other = SIN_PROXY;
2863f844a22SRuslan Ermilov 				argc--; argv++;
2873f844a22SRuslan Ermilov 			}
288dea673e9SRodney W. Grimes 		} else if (strncmp(argv[0], "trail", 5) == 0) {
289dea673e9SRodney W. Grimes 			printf("%s: Sending trailers is no longer supported\n",
290dea673e9SRodney W. Grimes 				host);
291dea673e9SRodney W. Grimes 		}
292dea673e9SRodney W. Grimes 		argv++;
293dea673e9SRodney W. Grimes 	}
294a42a667dSPoul-Henning Kamp 	ea = (u_char *)LLADDR(&sdl_m);
295a42a667dSPoul-Henning Kamp 	if (doing_proxy && !strcmp(eaddr, "auto")) {
296a42a667dSPoul-Henning Kamp 		if (!get_ether_addr(sin->sin_addr.s_addr, ea)) {
297eec827b0SRuslan Ermilov 			printf("no interface found for %s\n",
298eec827b0SRuslan Ermilov 			       inet_ntoa(sin->sin_addr));
299a42a667dSPoul-Henning Kamp 			return (1);
300a42a667dSPoul-Henning Kamp 		}
301a42a667dSPoul-Henning Kamp 		sdl_m.sdl_alen = 6;
302a42a667dSPoul-Henning Kamp 	} else {
30363c64400SNate Williams 		if (my_ether_aton(eaddr, ea) == 0)
304a42a667dSPoul-Henning Kamp 			sdl_m.sdl_alen = 6;
305a42a667dSPoul-Henning Kamp 	}
306dea673e9SRodney W. Grimes tryagain:
307dea673e9SRodney W. Grimes 	if (rtmsg(RTM_GET) < 0) {
308c72049e4SPhilippe Charnier 		warn("%s", host);
309dea673e9SRodney W. Grimes 		return (1);
310dea673e9SRodney W. Grimes 	}
311dea673e9SRodney W. Grimes 	sin = (struct sockaddr_inarp *)(rtm + 1);
3123a6a5ebeSRuslan Ermilov 	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin_len) + (char *)sin);
313dea673e9SRodney W. Grimes 	if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
314dea673e9SRodney W. Grimes 		if (sdl->sdl_family == AF_LINK &&
315dea673e9SRodney W. Grimes 		    (rtm->rtm_flags & RTF_LLINFO) &&
316dea673e9SRodney W. Grimes 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
317dea673e9SRodney W. Grimes 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
31888d5b613SYaroslav Tykhiy 		case IFT_ISO88024: case IFT_ISO88025: case IFT_L2VLAN:
319dea673e9SRodney W. Grimes 			goto overwrite;
320dea673e9SRodney W. Grimes 		}
321dea673e9SRodney W. Grimes 		if (doing_proxy == 0) {
322dea673e9SRodney W. Grimes 			printf("set: can only proxy for %s\n", host);
323dea673e9SRodney W. Grimes 			return (1);
324dea673e9SRodney W. Grimes 		}
325dea673e9SRodney W. Grimes 		if (sin_m.sin_other & SIN_PROXY) {
326dea673e9SRodney W. Grimes 			printf("set: proxy entry exists for non 802 device\n");
327dea673e9SRodney W. Grimes 			return(1);
328dea673e9SRodney W. Grimes 		}
329dea673e9SRodney W. Grimes 		sin_m.sin_other = SIN_PROXY;
3303f844a22SRuslan Ermilov 		proxy_only = 1;
331dea673e9SRodney W. Grimes 		goto tryagain;
332dea673e9SRodney W. Grimes 	}
333dea673e9SRodney W. Grimes overwrite:
334dea673e9SRodney W. Grimes 	if (sdl->sdl_family != AF_LINK) {
335dea673e9SRodney W. Grimes 		printf("cannot intuit interface index and type for %s\n", host);
336dea673e9SRodney W. Grimes 		return (1);
337dea673e9SRodney W. Grimes 	}
338dea673e9SRodney W. Grimes 	sdl_m.sdl_type = sdl->sdl_type;
339dea673e9SRodney W. Grimes 	sdl_m.sdl_index = sdl->sdl_index;
340dea673e9SRodney W. Grimes 	return (rtmsg(RTM_ADD));
341dea673e9SRodney W. Grimes }
342dea673e9SRodney W. Grimes 
343dea673e9SRodney W. Grimes /*
344dea673e9SRodney W. Grimes  * Display an individual arp entry
345dea673e9SRodney W. Grimes  */
3468dc4b495SJulian Elischer int
347a42a667dSPoul-Henning Kamp get(char *host)
348dea673e9SRodney W. Grimes {
349dea673e9SRodney W. Grimes 	struct hostent *hp;
350dea673e9SRodney W. Grimes 	struct sockaddr_inarp *sin = &sin_m;
351dea673e9SRodney W. Grimes 
352dea673e9SRodney W. Grimes 	sin_m = blank_sin;
353dea673e9SRodney W. Grimes 	sin->sin_addr.s_addr = inet_addr(host);
3543f844a22SRuslan Ermilov 	if (sin->sin_addr.s_addr == INADDR_NONE) {
355c72049e4SPhilippe Charnier 		if (!(hp = gethostbyname(host)))
356c72049e4SPhilippe Charnier 			errx(1, "%s: %s", host, hstrerror(h_errno));
357dea673e9SRodney W. Grimes 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
358dea673e9SRodney W. Grimes 		    sizeof sin->sin_addr);
359dea673e9SRodney W. Grimes 	}
3608dc4b495SJulian Elischer 	search(sin->sin_addr.s_addr, print_entry);
361dea673e9SRodney W. Grimes 	if (found_entry == 0) {
362dea673e9SRodney W. Grimes 		printf("%s (%s) -- no entry\n",
363dea673e9SRodney W. Grimes 		    host, inet_ntoa(sin->sin_addr));
3648dc4b495SJulian Elischer 		return(1);
365dea673e9SRodney W. Grimes 	}
3668dc4b495SJulian Elischer 	return(0);
367dea673e9SRodney W. Grimes }
368dea673e9SRodney W. Grimes 
369dea673e9SRodney W. Grimes /*
370dea673e9SRodney W. Grimes  * Delete an arp entry
371dea673e9SRodney W. Grimes  */
372a42a667dSPoul-Henning Kamp int
373a42a667dSPoul-Henning Kamp delete(char *host, char *info)
374dea673e9SRodney W. Grimes {
375dea673e9SRodney W. Grimes 	struct hostent *hp;
376dea673e9SRodney W. Grimes 	register struct sockaddr_inarp *sin = &sin_m;
377dea673e9SRodney W. Grimes 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
378dea673e9SRodney W. Grimes 	struct sockaddr_dl *sdl;
379dea673e9SRodney W. Grimes 
380dea673e9SRodney W. Grimes 	getsocket();
381dea673e9SRodney W. Grimes 	sin_m = blank_sin;
3823f844a22SRuslan Ermilov 	if (info) {
3833f844a22SRuslan Ermilov 		if (strncmp(info, "pub", 3) == 0)
3849ea1ba64SRuslan Ermilov 			sin_m.sin_other = SIN_PROXY;
3853f844a22SRuslan Ermilov 		else
3863f844a22SRuslan Ermilov 			usage();
3873f844a22SRuslan Ermilov 	}
388dea673e9SRodney W. Grimes 	sin->sin_addr.s_addr = inet_addr(host);
3893f844a22SRuslan Ermilov 	if (sin->sin_addr.s_addr == INADDR_NONE) {
390dea673e9SRodney W. Grimes 		if (!(hp = gethostbyname(host))) {
391c72049e4SPhilippe Charnier 			warnx("%s: %s", host, hstrerror(h_errno));
392dea673e9SRodney W. Grimes 			return (1);
393dea673e9SRodney W. Grimes 		}
394dea673e9SRodney W. Grimes 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
395dea673e9SRodney W. Grimes 		    sizeof sin->sin_addr);
396dea673e9SRodney W. Grimes 	}
397dea673e9SRodney W. Grimes tryagain:
398dea673e9SRodney W. Grimes 	if (rtmsg(RTM_GET) < 0) {
399c72049e4SPhilippe Charnier 		warn("%s", host);
400dea673e9SRodney W. Grimes 		return (1);
401dea673e9SRodney W. Grimes 	}
402dea673e9SRodney W. Grimes 	sin = (struct sockaddr_inarp *)(rtm + 1);
4033a6a5ebeSRuslan Ermilov 	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin_len) + (char *)sin);
404dea673e9SRodney W. Grimes 	if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
405dea673e9SRodney W. Grimes 		if (sdl->sdl_family == AF_LINK &&
406dea673e9SRodney W. Grimes 		    (rtm->rtm_flags & RTF_LLINFO) &&
407dea673e9SRodney W. Grimes 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
408dea673e9SRodney W. Grimes 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
40988d5b613SYaroslav Tykhiy 		case IFT_ISO88024: case IFT_ISO88025: case IFT_L2VLAN:
410dea673e9SRodney W. Grimes 			goto delete;
411dea673e9SRodney W. Grimes 		}
412dea673e9SRodney W. Grimes 	}
413dea673e9SRodney W. Grimes 	if (sin_m.sin_other & SIN_PROXY) {
414dea673e9SRodney W. Grimes 		fprintf(stderr, "delete: can't locate %s\n",host);
415dea673e9SRodney W. Grimes 		return (1);
416dea673e9SRodney W. Grimes 	} else {
417dea673e9SRodney W. Grimes 		sin_m.sin_other = SIN_PROXY;
418dea673e9SRodney W. Grimes 		goto tryagain;
419dea673e9SRodney W. Grimes 	}
420dea673e9SRodney W. Grimes delete:
421dea673e9SRodney W. Grimes 	if (sdl->sdl_family != AF_LINK) {
422dea673e9SRodney W. Grimes 		printf("cannot locate %s\n", host);
423dea673e9SRodney W. Grimes 		return (1);
424dea673e9SRodney W. Grimes 	}
425a42a667dSPoul-Henning Kamp 	if (rtmsg(RTM_DELETE) == 0) {
426dea673e9SRodney W. Grimes 		printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
427a42a667dSPoul-Henning Kamp 		return (0);
428a42a667dSPoul-Henning Kamp 	}
429a42a667dSPoul-Henning Kamp 	return (1);
430dea673e9SRodney W. Grimes }
431dea673e9SRodney W. Grimes 
432dea673e9SRodney W. Grimes /*
4338dc4b495SJulian Elischer  * Search the arp table and do some action on matching entries
434dea673e9SRodney W. Grimes  */
435a42a667dSPoul-Henning Kamp void
4368dc4b495SJulian Elischer search(u_long addr, void (*action)(struct sockaddr_dl *sdl,
4378dc4b495SJulian Elischer 	struct sockaddr_inarp *sin, struct rt_msghdr *rtm))
438dea673e9SRodney W. Grimes {
439dea673e9SRodney W. Grimes 	int mib[6];
440dea673e9SRodney W. Grimes 	size_t needed;
4418dc4b495SJulian Elischer 	char *lim, *buf, *next;
442dea673e9SRodney W. Grimes 	struct rt_msghdr *rtm;
443dea673e9SRodney W. Grimes 	struct sockaddr_inarp *sin;
444dea673e9SRodney W. Grimes 	struct sockaddr_dl *sdl;
445dea673e9SRodney W. Grimes 
446dea673e9SRodney W. Grimes 	mib[0] = CTL_NET;
447dea673e9SRodney W. Grimes 	mib[1] = PF_ROUTE;
448dea673e9SRodney W. Grimes 	mib[2] = 0;
449dea673e9SRodney W. Grimes 	mib[3] = AF_INET;
450dea673e9SRodney W. Grimes 	mib[4] = NET_RT_FLAGS;
451dea673e9SRodney W. Grimes 	mib[5] = RTF_LLINFO;
452dea673e9SRodney W. Grimes 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
453c72049e4SPhilippe Charnier 		errx(1, "route-sysctl-estimate");
454dea673e9SRodney W. Grimes 	if ((buf = malloc(needed)) == NULL)
455c72049e4SPhilippe Charnier 		errx(1, "malloc");
456dea673e9SRodney W. Grimes 	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
457c72049e4SPhilippe Charnier 		errx(1, "actual retrieval of routing table");
458dea673e9SRodney W. Grimes 	lim = buf + needed;
459dea673e9SRodney W. Grimes 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
460dea673e9SRodney W. Grimes 		rtm = (struct rt_msghdr *)next;
461dea673e9SRodney W. Grimes 		sin = (struct sockaddr_inarp *)(rtm + 1);
46208e13cdfSRuslan Ermilov 		(char *)sdl = (char *)sin + ROUNDUP(sin->sin_len);
463dea673e9SRodney W. Grimes 		if (addr) {
464dea673e9SRodney W. Grimes 			if (addr != sin->sin_addr.s_addr)
465dea673e9SRodney W. Grimes 				continue;
466dea673e9SRodney W. Grimes 			found_entry = 1;
467dea673e9SRodney W. Grimes 		}
4688dc4b495SJulian Elischer 		(*action)(sdl, sin, rtm);
4698dc4b495SJulian Elischer 	}
470ae14be20SYaroslav Tykhiy 	free(buf);
4718dc4b495SJulian Elischer }
4728dc4b495SJulian Elischer 
4738dc4b495SJulian Elischer /*
4748dc4b495SJulian Elischer  * Display an arp entry
4758dc4b495SJulian Elischer  */
4768dc4b495SJulian Elischer void
4778dc4b495SJulian Elischer print_entry(struct sockaddr_dl *sdl,
4788dc4b495SJulian Elischer 	struct sockaddr_inarp *sin, struct rt_msghdr *rtm)
4798dc4b495SJulian Elischer {
4803f844a22SRuslan Ermilov 	const char *host;
4818dc4b495SJulian Elischer 	struct hostent *hp;
482e87a372bSRuslan Ermilov 	char ifname[IF_NAMESIZE];
483fda82fc2SJulian Elischer 	int seg;
4848dc4b495SJulian Elischer 
485dea673e9SRodney W. Grimes 	if (nflag == 0)
486dea673e9SRodney W. Grimes 		hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
487dea673e9SRodney W. Grimes 		    sizeof sin->sin_addr, AF_INET);
488dea673e9SRodney W. Grimes 	else
489dea673e9SRodney W. Grimes 		hp = 0;
490dea673e9SRodney W. Grimes 	if (hp)
491dea673e9SRodney W. Grimes 		host = hp->h_name;
492dea673e9SRodney W. Grimes 	else {
493dea673e9SRodney W. Grimes 		host = "?";
494dea673e9SRodney W. Grimes 		if (h_errno == TRY_AGAIN)
495dea673e9SRodney W. Grimes 			nflag = 1;
496dea673e9SRodney W. Grimes 	}
497dea673e9SRodney W. Grimes 	printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
498dea673e9SRodney W. Grimes 	if (sdl->sdl_alen)
499dea673e9SRodney W. Grimes 		ether_print(LLADDR(sdl));
500dea673e9SRodney W. Grimes 	else
501dea673e9SRodney W. Grimes 		printf("(incomplete)");
502e87a372bSRuslan Ermilov 	if (if_indextoname(sdl->sdl_index, ifname) != NULL)
503e87a372bSRuslan Ermilov 		printf(" on %s", ifname);
504dea673e9SRodney W. Grimes 	if (rtm->rtm_rmx.rmx_expire == 0)
505dea673e9SRodney W. Grimes 		printf(" permanent");
506dea673e9SRodney W. Grimes 	if (sin->sin_other & SIN_PROXY)
507dea673e9SRodney W. Grimes 		printf(" published (proxy only)");
508dea673e9SRodney W. Grimes 	if (rtm->rtm_addrs & RTA_NETMASK) {
509dea673e9SRodney W. Grimes 		sin = (struct sockaddr_inarp *)
5103a6a5ebeSRuslan Ermilov 			(ROUNDUP(sdl->sdl_len) + (char *)sdl);
511dea673e9SRodney W. Grimes 		if (sin->sin_addr.s_addr == 0xffffffff)
512dea673e9SRodney W. Grimes 			printf(" published");
513dea673e9SRodney W. Grimes 		if (sin->sin_len != 8)
5143a6a5ebeSRuslan Ermilov 			printf("(weird)");
515dea673e9SRodney W. Grimes 	}
516fda82fc2SJulian Elischer         switch(sdl->sdl_type) {
517fda82fc2SJulian Elischer             case IFT_ETHER:
518fda82fc2SJulian Elischer                 printf(" [ethernet]");
519fda82fc2SJulian Elischer                 break;
520fda82fc2SJulian Elischer             case IFT_ISO88025:
521fda82fc2SJulian Elischer                 printf(" [token-ring]");
522fda82fc2SJulian Elischer                 break;
52304427472SMatthew N. Dodd             case IFT_FDDI:
52404427472SMatthew N. Dodd                 printf(" [fddi]");
52504427472SMatthew N. Dodd                 break;
52604427472SMatthew N. Dodd             case IFT_ATM:
52704427472SMatthew N. Dodd                 printf(" [atm]");
52804427472SMatthew N. Dodd                 break;
52988d5b613SYaroslav Tykhiy 	    case IFT_L2VLAN:
53088d5b613SYaroslav Tykhiy 		printf(" [vlan]");
53188d5b613SYaroslav Tykhiy 		break;
532fda82fc2SJulian Elischer             default:
533fda82fc2SJulian Elischer         }
534fda82fc2SJulian Elischer 	if (sdl->sdl_rcf != NULL) {
535fda82fc2SJulian Elischer 		printf(" rt=%x", ntohs(sdl->sdl_rcf));
536fda82fc2SJulian Elischer 		for (seg = 0; seg < ((((ntohs(sdl->sdl_rcf) & 0x1f00) >> 8) - 2 ) / 2); seg++)
537fda82fc2SJulian Elischer 			printf(":%x", ntohs(sdl->sdl_route[seg]));
538fda82fc2SJulian Elischer 	}
539fda82fc2SJulian Elischer 
540dea673e9SRodney W. Grimes 	printf("\n");
541fda82fc2SJulian Elischer 
542dea673e9SRodney W. Grimes }
5438dc4b495SJulian Elischer 
5448dc4b495SJulian Elischer /*
5458dc4b495SJulian Elischer  * Nuke an arp entry
5468dc4b495SJulian Elischer  */
5478dc4b495SJulian Elischer void
5488dc4b495SJulian Elischer nuke_entry(struct sockaddr_dl *sdl,
5498dc4b495SJulian Elischer 	struct sockaddr_inarp *sin, struct rt_msghdr *rtm)
5508dc4b495SJulian Elischer {
5518dc4b495SJulian Elischer 	char ip[20];
5528dc4b495SJulian Elischer 
5538dc4b495SJulian Elischer 	snprintf(ip, sizeof(ip), "%s", inet_ntoa(sin->sin_addr));
5548dc4b495SJulian Elischer 	delete(ip, NULL);
555dea673e9SRodney W. Grimes }
556dea673e9SRodney W. Grimes 
557a42a667dSPoul-Henning Kamp void
558a42a667dSPoul-Henning Kamp ether_print(u_char *cp)
559dea673e9SRodney W. Grimes {
5605651a036SBill Fumerola 	printf("%02x:%02x:%02x:%02x:%02x:%02x", cp[0], cp[1], cp[2], cp[3],
5615651a036SBill Fumerola 						cp[4], cp[5]);
562dea673e9SRodney W. Grimes }
563dea673e9SRodney W. Grimes 
564a42a667dSPoul-Henning Kamp int
56563c64400SNate Williams my_ether_aton(char *a, u_char *n)
566dea673e9SRodney W. Grimes {
567dea673e9SRodney W. Grimes 	int i, o[6];
568dea673e9SRodney W. Grimes 
569dea673e9SRodney W. Grimes 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
570dea673e9SRodney W. Grimes 					   &o[3], &o[4], &o[5]);
571dea673e9SRodney W. Grimes 	if (i != 6) {
572c72049e4SPhilippe Charnier 		warnx("invalid Ethernet address '%s'", a);
573dea673e9SRodney W. Grimes 		return (1);
574dea673e9SRodney W. Grimes 	}
575dea673e9SRodney W. Grimes 	for (i=0; i<6; i++)
576dea673e9SRodney W. Grimes 		n[i] = o[i];
577dea673e9SRodney W. Grimes 	return (0);
578dea673e9SRodney W. Grimes }
579dea673e9SRodney W. Grimes 
580a42a667dSPoul-Henning Kamp void
581a42a667dSPoul-Henning Kamp usage(void)
582dea673e9SRodney W. Grimes {
5838dc4b495SJulian Elischer 	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
584c72049e4SPhilippe Charnier 		"usage: arp [-n] hostname",
5858dc4b495SJulian Elischer 		"       arp [-n] -a",
5863f844a22SRuslan Ermilov 		"       arp -d hostname [pub]",
5878dc4b495SJulian Elischer 		"       arp -d -a",
588c72049e4SPhilippe Charnier 		"       arp -s hostname ether_addr [temp] [pub]",
589c72049e4SPhilippe Charnier 		"       arp -S hostname ether_addr [temp] [pub]",
590c72049e4SPhilippe Charnier 		"       arp -f filename");
591dea673e9SRodney W. Grimes 	exit(1);
592dea673e9SRodney W. Grimes }
593dea673e9SRodney W. Grimes 
594a42a667dSPoul-Henning Kamp int
595a42a667dSPoul-Henning Kamp rtmsg(int cmd)
596dea673e9SRodney W. Grimes {
597dea673e9SRodney W. Grimes 	static int seq;
598dea673e9SRodney W. Grimes 	int rlen;
599dea673e9SRodney W. Grimes 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
600dea673e9SRodney W. Grimes 	register char *cp = m_rtmsg.m_space;
601dea673e9SRodney W. Grimes 	register int l;
602dea673e9SRodney W. Grimes 
603dea673e9SRodney W. Grimes 	errno = 0;
604dea673e9SRodney W. Grimes 	if (cmd == RTM_DELETE)
605dea673e9SRodney W. Grimes 		goto doit;
606dea673e9SRodney W. Grimes 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
607dea673e9SRodney W. Grimes 	rtm->rtm_flags = flags;
608dea673e9SRodney W. Grimes 	rtm->rtm_version = RTM_VERSION;
609dea673e9SRodney W. Grimes 
610dea673e9SRodney W. Grimes 	switch (cmd) {
611dea673e9SRodney W. Grimes 	default:
612c72049e4SPhilippe Charnier 		errx(1, "internal wrong cmd");
613dea673e9SRodney W. Grimes 	case RTM_ADD:
614dea673e9SRodney W. Grimes 		rtm->rtm_addrs |= RTA_GATEWAY;
615dea673e9SRodney W. Grimes 		rtm->rtm_rmx.rmx_expire = expire_time;
616dea673e9SRodney W. Grimes 		rtm->rtm_inits = RTV_EXPIRE;
617dea673e9SRodney W. Grimes 		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
618dea673e9SRodney W. Grimes 		sin_m.sin_other = 0;
619dea673e9SRodney W. Grimes 		if (doing_proxy) {
6203f844a22SRuslan Ermilov 			if (proxy_only)
621dea673e9SRodney W. Grimes 				sin_m.sin_other = SIN_PROXY;
622dea673e9SRodney W. Grimes 			else {
623dea673e9SRodney W. Grimes 				rtm->rtm_addrs |= RTA_NETMASK;
624dea673e9SRodney W. Grimes 				rtm->rtm_flags &= ~RTF_HOST;
625dea673e9SRodney W. Grimes 			}
626dea673e9SRodney W. Grimes 		}
627dea673e9SRodney W. Grimes 		/* FALLTHROUGH */
628dea673e9SRodney W. Grimes 	case RTM_GET:
629dea673e9SRodney W. Grimes 		rtm->rtm_addrs |= RTA_DST;
630dea673e9SRodney W. Grimes 	}
631dea673e9SRodney W. Grimes #define NEXTADDR(w, s) \
632dea673e9SRodney W. Grimes 	if (rtm->rtm_addrs & (w)) { \
6333a6a5ebeSRuslan Ermilov 		bcopy((char *)&s, cp, sizeof(s)); cp += ROUNDUP(sizeof(s));}
634dea673e9SRodney W. Grimes 
635dea673e9SRodney W. Grimes 	NEXTADDR(RTA_DST, sin_m);
636dea673e9SRodney W. Grimes 	NEXTADDR(RTA_GATEWAY, sdl_m);
637dea673e9SRodney W. Grimes 	NEXTADDR(RTA_NETMASK, so_mask);
638dea673e9SRodney W. Grimes 
639dea673e9SRodney W. Grimes 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
640dea673e9SRodney W. Grimes doit:
641dea673e9SRodney W. Grimes 	l = rtm->rtm_msglen;
642dea673e9SRodney W. Grimes 	rtm->rtm_seq = ++seq;
643dea673e9SRodney W. Grimes 	rtm->rtm_type = cmd;
644dea673e9SRodney W. Grimes 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
645dea673e9SRodney W. Grimes 		if (errno != ESRCH || cmd != RTM_DELETE) {
646c72049e4SPhilippe Charnier 			warn("writing to routing socket");
647dea673e9SRodney W. Grimes 			return (-1);
648dea673e9SRodney W. Grimes 		}
649dea673e9SRodney W. Grimes 	}
650dea673e9SRodney W. Grimes 	do {
651dea673e9SRodney W. Grimes 		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
652dea673e9SRodney W. Grimes 	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
653dea673e9SRodney W. Grimes 	if (l < 0)
654c72049e4SPhilippe Charnier 		warn("read from routing socket");
655dea673e9SRodney W. Grimes 	return (0);
656dea673e9SRodney W. Grimes }
657dea673e9SRodney W. Grimes 
658a42a667dSPoul-Henning Kamp /*
659a42a667dSPoul-Henning Kamp  * get_ether_addr - get the hardware address of an interface on the
660a42a667dSPoul-Henning Kamp  * the same subnet as ipaddr.
661a42a667dSPoul-Henning Kamp  */
662a42a667dSPoul-Henning Kamp #define MAX_IFS		32
663a42a667dSPoul-Henning Kamp 
664a42a667dSPoul-Henning Kamp int
6651fece1a6SYoshinobu Inoue get_ether_addr(u_int32_t ipaddr, u_char *hwaddr)
666a42a667dSPoul-Henning Kamp {
667a42a667dSPoul-Henning Kamp 	struct ifreq *ifr, *ifend, *ifp;
6681fece1a6SYoshinobu Inoue 	u_int32_t ina, mask;
669a42a667dSPoul-Henning Kamp 	struct sockaddr_dl *dla;
670a42a667dSPoul-Henning Kamp 	struct ifreq ifreq;
671a42a667dSPoul-Henning Kamp 	struct ifconf ifc;
672a42a667dSPoul-Henning Kamp 	struct ifreq ifs[MAX_IFS];
673a42a667dSPoul-Henning Kamp 	int s;
674a42a667dSPoul-Henning Kamp 
675a42a667dSPoul-Henning Kamp 	s = socket(AF_INET, SOCK_DGRAM, 0);
676c72049e4SPhilippe Charnier 	if (s < 0)
677c72049e4SPhilippe Charnier 		err(1, "socket");
678a42a667dSPoul-Henning Kamp 
679a42a667dSPoul-Henning Kamp 	ifc.ifc_len = sizeof(ifs);
680a42a667dSPoul-Henning Kamp 	ifc.ifc_req = ifs;
681a42a667dSPoul-Henning Kamp 	if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
682c72049e4SPhilippe Charnier 		warnx("ioctl(SIOCGIFCONF)");
683a42a667dSPoul-Henning Kamp 		close(s);
684a42a667dSPoul-Henning Kamp 		return 0;
685a42a667dSPoul-Henning Kamp 	}
686a42a667dSPoul-Henning Kamp 
687a42a667dSPoul-Henning Kamp 	/*
688a42a667dSPoul-Henning Kamp 	* Scan through looking for an interface with an Internet
689a42a667dSPoul-Henning Kamp 	* address on the same subnet as `ipaddr'.
690a42a667dSPoul-Henning Kamp 	*/
691a42a667dSPoul-Henning Kamp 	ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
692a42a667dSPoul-Henning Kamp 	for (ifr = ifc.ifc_req; ifr < ifend; ) {
693a42a667dSPoul-Henning Kamp 		if (ifr->ifr_addr.sa_family == AF_INET) {
694a42a667dSPoul-Henning Kamp 			ina = ((struct sockaddr_in *)
695a42a667dSPoul-Henning Kamp 				&ifr->ifr_addr)->sin_addr.s_addr;
696a42a667dSPoul-Henning Kamp 			strncpy(ifreq.ifr_name, ifr->ifr_name,
697a42a667dSPoul-Henning Kamp 				sizeof(ifreq.ifr_name));
698a42a667dSPoul-Henning Kamp 			/*
699a42a667dSPoul-Henning Kamp 			 * Check that the interface is up,
700a42a667dSPoul-Henning Kamp 			 * and not point-to-point or loopback.
701a42a667dSPoul-Henning Kamp 			 */
702a42a667dSPoul-Henning Kamp 			if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
703a42a667dSPoul-Henning Kamp 				continue;
704a42a667dSPoul-Henning Kamp 			if ((ifreq.ifr_flags &
705a42a667dSPoul-Henning Kamp 			     (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
706a42a667dSPoul-Henning Kamp 					IFF_LOOPBACK|IFF_NOARP))
707a42a667dSPoul-Henning Kamp 			     != (IFF_UP|IFF_BROADCAST))
708a42a667dSPoul-Henning Kamp 				goto nextif;
709a42a667dSPoul-Henning Kamp 			/*
710a42a667dSPoul-Henning Kamp 			 * Get its netmask and check that it's on
711a42a667dSPoul-Henning Kamp 			 * the right subnet.
712a42a667dSPoul-Henning Kamp 			 */
713a42a667dSPoul-Henning Kamp 			if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
714a42a667dSPoul-Henning Kamp 				continue;
715a42a667dSPoul-Henning Kamp 			mask = ((struct sockaddr_in *)
716a42a667dSPoul-Henning Kamp 				&ifreq.ifr_addr)->sin_addr.s_addr;
717a42a667dSPoul-Henning Kamp 			if ((ipaddr & mask) != (ina & mask))
718a42a667dSPoul-Henning Kamp 				goto nextif;
719a42a667dSPoul-Henning Kamp 			break;
720a42a667dSPoul-Henning Kamp 		}
721a42a667dSPoul-Henning Kamp nextif:
7223816c56cSArchie Cobbs 		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
7233816c56cSArchie Cobbs 		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
724a42a667dSPoul-Henning Kamp 	}
725a42a667dSPoul-Henning Kamp 
726a42a667dSPoul-Henning Kamp 	if (ifr >= ifend) {
727a42a667dSPoul-Henning Kamp 		close(s);
728a42a667dSPoul-Henning Kamp 		return 0;
729a42a667dSPoul-Henning Kamp 	}
730a42a667dSPoul-Henning Kamp 
731a42a667dSPoul-Henning Kamp 	/*
732a42a667dSPoul-Henning Kamp 	* Now scan through again looking for a link-level address
733a42a667dSPoul-Henning Kamp 	* for this interface.
734a42a667dSPoul-Henning Kamp 	*/
735a42a667dSPoul-Henning Kamp 	ifp = ifr;
736a42a667dSPoul-Henning Kamp 	for (ifr = ifc.ifc_req; ifr < ifend; ) {
737a42a667dSPoul-Henning Kamp 		if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
738a42a667dSPoul-Henning Kamp 		    && ifr->ifr_addr.sa_family == AF_LINK) {
739a42a667dSPoul-Henning Kamp 			/*
740a42a667dSPoul-Henning Kamp 			 * Found the link-level address - copy it out
741a42a667dSPoul-Henning Kamp 			 */
742a42a667dSPoul-Henning Kamp 		 	dla = (struct sockaddr_dl *) &ifr->ifr_addr;
743a42a667dSPoul-Henning Kamp 			memcpy(hwaddr,  LLADDR(dla), dla->sdl_alen);
744a42a667dSPoul-Henning Kamp 			close (s);
745a42a667dSPoul-Henning Kamp 			printf("using interface %s for proxy with address ",
746a42a667dSPoul-Henning Kamp 				ifp->ifr_name);
747a42a667dSPoul-Henning Kamp 			ether_print(hwaddr);
748a42a667dSPoul-Henning Kamp 			printf("\n");
749a42a667dSPoul-Henning Kamp 			return dla->sdl_alen;
750a42a667dSPoul-Henning Kamp 		}
7513816c56cSArchie Cobbs 		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
7523816c56cSArchie Cobbs 		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
753a42a667dSPoul-Henning Kamp 	}
754a42a667dSPoul-Henning Kamp 	return 0;
755a42a667dSPoul-Henning Kamp }
756