xref: /freebsd/usr.sbin/arp/arp.c (revision 97fe20b4d0f6e4c057a01edd003ddd3c5ef57c3a)
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>
6797fe20b4SKelly Yancey #include <net/iso88025.h>
68dea673e9SRodney W. Grimes #include <net/route.h>
69dea673e9SRodney W. Grimes 
70dea673e9SRodney W. Grimes #include <netinet/in.h>
71dea673e9SRodney W. Grimes #include <netinet/if_ether.h>
72dea673e9SRodney W. Grimes 
73dea673e9SRodney W. Grimes #include <arpa/inet.h>
74dea673e9SRodney W. Grimes 
75c72049e4SPhilippe Charnier #include <err.h>
76dea673e9SRodney W. Grimes #include <errno.h>
77c72049e4SPhilippe Charnier #include <netdb.h>
78dea673e9SRodney W. Grimes #include <nlist.h>
79c72049e4SPhilippe Charnier #include <paths.h>
80dea673e9SRodney W. Grimes #include <stdio.h>
81a42a667dSPoul-Henning Kamp #include <stdlib.h>
82467a0b06SMike Barcroft #include <string.h>
83a42a667dSPoul-Henning Kamp #include <strings.h>
84c72049e4SPhilippe Charnier #include <unistd.h>
85dea673e9SRodney W. Grimes 
868dc4b495SJulian Elischer void search(u_long addr, void (*action)(struct sockaddr_dl *sdl,
878dc4b495SJulian Elischer 	struct sockaddr_inarp *sin, struct rt_msghdr *rtm));
888dc4b495SJulian Elischer void print_entry(struct sockaddr_dl *sdl,
899d34414bSMike Heffner 	struct sockaddr_inarp *addr, struct rt_msghdr *rtm);
908dc4b495SJulian Elischer void nuke_entry(struct sockaddr_dl *sdl,
919d34414bSMike Heffner 	struct sockaddr_inarp *addr, struct rt_msghdr *rtm);
92a42a667dSPoul-Henning Kamp int delete(char *host, char *info);
93a42a667dSPoul-Henning Kamp void usage(void);
94a42a667dSPoul-Henning Kamp int set(int argc, char **argv);
958dc4b495SJulian Elischer int get(char *host);
96a42a667dSPoul-Henning Kamp int file(char *name);
97a42a667dSPoul-Henning Kamp void getsocket(void);
98a03b1b7cSRuslan Ermilov int my_ether_aton(char *a, struct ether_addr *n);
99a42a667dSPoul-Henning Kamp int rtmsg(int cmd);
100a03b1b7cSRuslan Ermilov int get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr);
101a42a667dSPoul-Henning Kamp 
102dea673e9SRodney W. Grimes static int pid;
1038dc4b495SJulian Elischer static int nflag;	/* no reverse dns lookups */
1048dc4b495SJulian Elischer static int aflag;	/* do it for all entries */
105dea673e9SRodney W. Grimes static int s = -1;
106dea673e9SRodney W. Grimes 
1079d34414bSMike Heffner struct	sockaddr_in so_mask;
1089d34414bSMike Heffner struct	sockaddr_inarp blank_sin, sin_m;
1099d34414bSMike Heffner struct	sockaddr_dl blank_sdl, sdl_m;
1109d34414bSMike Heffner int	expire_time, flags, doing_proxy, proxy_only, found_entry;
1119d34414bSMike Heffner struct	{
1129d34414bSMike Heffner 	struct	rt_msghdr m_rtm;
1139d34414bSMike Heffner 	char	m_space[512];
1149d34414bSMike Heffner }	m_rtmsg;
1159d34414bSMike Heffner 
1168dc4b495SJulian Elischer /* which function we're supposed to do */
1178dc4b495SJulian Elischer #define F_GET		1
1188dc4b495SJulian Elischer #define F_SET		2
1198dc4b495SJulian Elischer #define F_FILESET	3
1208dc4b495SJulian Elischer #define F_REPLACE	4
1218dc4b495SJulian Elischer #define F_DELETE	5
1228dc4b495SJulian Elischer 
1233a6a5ebeSRuslan Ermilov #define ROUNDUP(a) \
1243a6a5ebeSRuslan Ermilov 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1258dc4b495SJulian Elischer #define SETFUNC(f)	{ if (func) usage(); func = (f); }
1268dc4b495SJulian Elischer 
127a42a667dSPoul-Henning Kamp int
1283f844a22SRuslan Ermilov main(int argc, char *argv[])
129dea673e9SRodney W. Grimes {
1308dc4b495SJulian Elischer 	int ch, func = 0;
1318dc4b495SJulian Elischer 	int rtn = 0;
132dea673e9SRodney W. Grimes 
133dea673e9SRodney W. Grimes 	pid = getpid();
1346c3f552aSWarner Losh 	while ((ch = getopt(argc, argv, "andfsS")) != -1)
135dea673e9SRodney W. Grimes 		switch((char)ch) {
136dea673e9SRodney W. Grimes 		case 'a':
1378dc4b495SJulian Elischer 			aflag = 1;
1388dc4b495SJulian Elischer 			break;
139dea673e9SRodney W. Grimes 		case 'd':
1408dc4b495SJulian Elischer 			SETFUNC(F_DELETE);
1418dc4b495SJulian Elischer 			break;
142dea673e9SRodney W. Grimes 		case 'n':
143dea673e9SRodney W. Grimes 			nflag = 1;
1448dc4b495SJulian Elischer 			break;
145a42a667dSPoul-Henning Kamp 		case 'S':
1468dc4b495SJulian Elischer 			SETFUNC(F_REPLACE);
1478dc4b495SJulian Elischer 			break;
148dea673e9SRodney W. Grimes 		case 's':
1498dc4b495SJulian Elischer 			SETFUNC(F_SET);
1508dc4b495SJulian Elischer 			break;
15195319e17SJordan K. Hubbard 		case 'f' :
1528dc4b495SJulian Elischer 			SETFUNC(F_FILESET);
1538dc4b495SJulian Elischer 			break;
154dea673e9SRodney W. Grimes 		case '?':
155dea673e9SRodney W. Grimes 		default:
156dea673e9SRodney W. Grimes 			usage();
157dea673e9SRodney W. Grimes 		}
1588dc4b495SJulian Elischer 	argc -= optind;
1598dc4b495SJulian Elischer 	argv += optind;
1608dc4b495SJulian Elischer 
1619d34414bSMike Heffner 	bzero(&so_mask, sizeof(so_mask));
1629cc7cb58SMike Heffner 	so_mask.sin_len = 8;
1639d34414bSMike Heffner 	so_mask.sin_addr.s_addr = 0xffffffff;
1649d34414bSMike Heffner 	bzero(&blank_sin, sizeof(blank_sin));
1659d34414bSMike Heffner 	blank_sin.sin_len = sizeof(blank_sin);
1669d34414bSMike Heffner 	blank_sin.sin_family = AF_INET;
1679d34414bSMike Heffner 	bzero(&blank_sdl, sizeof(blank_sdl));
1689d34414bSMike Heffner 	blank_sdl.sdl_len = sizeof(blank_sdl);
1699d34414bSMike Heffner 	blank_sdl.sdl_family = AF_LINK;
1709d34414bSMike Heffner 
1718dc4b495SJulian Elischer 	if (!func)
1728dc4b495SJulian Elischer 		func = F_GET;
1738dc4b495SJulian Elischer 	switch (func) {
1748dc4b495SJulian Elischer 	case F_GET:
1758dc4b495SJulian Elischer 		if (aflag) {
1768dc4b495SJulian Elischer 			if (argc != 0)
177dea673e9SRodney W. Grimes 				usage();
1788dc4b495SJulian Elischer 			search(0, print_entry);
1798dc4b495SJulian Elischer 		} else {
1808dc4b495SJulian Elischer 			if (argc != 1)
1818dc4b495SJulian Elischer 				usage();
1828dc4b495SJulian Elischer 			get(argv[0]);
1838dc4b495SJulian Elischer 		}
1848dc4b495SJulian Elischer 		break;
1858dc4b495SJulian Elischer 	case F_SET:
1868dc4b495SJulian Elischer 	case F_REPLACE:
1873f844a22SRuslan Ermilov 		if (argc < 2 || argc > 6)
1888dc4b495SJulian Elischer 			usage();
1898dc4b495SJulian Elischer 		if (func == F_REPLACE)
1908dc4b495SJulian Elischer 			(void) delete(argv[0], NULL);
1918dc4b495SJulian Elischer 		rtn = set(argc, argv) ? 1 : 0;
1928dc4b495SJulian Elischer 		break;
1938dc4b495SJulian Elischer 	case F_DELETE:
1948dc4b495SJulian Elischer 		if (aflag) {
1958dc4b495SJulian Elischer 			if (argc != 0)
1968dc4b495SJulian Elischer 				usage();
1978dc4b495SJulian Elischer 			search(0, nuke_entry);
1988dc4b495SJulian Elischer 		} else {
1998dc4b495SJulian Elischer 			if (argc < 1 || argc > 2)
2008dc4b495SJulian Elischer 				usage();
2018dc4b495SJulian Elischer 			rtn = delete(argv[0], argv[1]);
2028dc4b495SJulian Elischer 		}
2038dc4b495SJulian Elischer 		break;
2048dc4b495SJulian Elischer 	case F_FILESET:
2058dc4b495SJulian Elischer 		if (argc != 1)
2068dc4b495SJulian Elischer 			usage();
2078dc4b495SJulian Elischer 		rtn = file(argv[0]);
2088dc4b495SJulian Elischer 		break;
2098dc4b495SJulian Elischer 	}
2108dc4b495SJulian Elischer 
2118dc4b495SJulian Elischer 	return(rtn);
212dea673e9SRodney W. Grimes }
213dea673e9SRodney W. Grimes 
214dea673e9SRodney W. Grimes /*
215dea673e9SRodney W. Grimes  * Process a file to set standard arp entries
216dea673e9SRodney W. Grimes  */
217a42a667dSPoul-Henning Kamp int
218a42a667dSPoul-Henning Kamp file(char *name)
219dea673e9SRodney W. Grimes {
220dea673e9SRodney W. Grimes 	FILE *fp;
221dea673e9SRodney W. Grimes 	int i, retval;
222dea673e9SRodney W. Grimes 	char line[100], arg[5][50], *args[5];
223dea673e9SRodney W. Grimes 
224c72049e4SPhilippe Charnier 	if ((fp = fopen(name, "r")) == NULL)
225c72049e4SPhilippe Charnier 		errx(1, "cannot open %s", name);
226dea673e9SRodney W. Grimes 	args[0] = &arg[0][0];
227dea673e9SRodney W. Grimes 	args[1] = &arg[1][0];
228dea673e9SRodney W. Grimes 	args[2] = &arg[2][0];
229dea673e9SRodney W. Grimes 	args[3] = &arg[3][0];
230dea673e9SRodney W. Grimes 	args[4] = &arg[4][0];
231dea673e9SRodney W. Grimes 	retval = 0;
232dea673e9SRodney W. Grimes 	while(fgets(line, 100, fp) != NULL) {
2330cecd500SKris Kennaway 		i = sscanf(line, "%49s %49s %49s %49s %49s", arg[0], arg[1],
234135adb1eSJordan K. Hubbard 		    arg[2], arg[3], arg[4]);
235dea673e9SRodney W. Grimes 		if (i < 2) {
236c72049e4SPhilippe Charnier 			warnx("bad line: %s", line);
237dea673e9SRodney W. Grimes 			retval = 1;
238dea673e9SRodney W. Grimes 			continue;
239dea673e9SRodney W. Grimes 		}
240dea673e9SRodney W. Grimes 		if (set(i, args))
241dea673e9SRodney W. Grimes 			retval = 1;
242dea673e9SRodney W. Grimes 	}
243dea673e9SRodney W. Grimes 	fclose(fp);
244dea673e9SRodney W. Grimes 	return (retval);
245dea673e9SRodney W. Grimes }
246dea673e9SRodney W. Grimes 
247a42a667dSPoul-Henning Kamp void
248a42a667dSPoul-Henning Kamp getsocket(void)
249a42a667dSPoul-Henning Kamp {
250dea673e9SRodney W. Grimes 	if (s < 0) {
251dea673e9SRodney W. Grimes 		s = socket(PF_ROUTE, SOCK_RAW, 0);
252c72049e4SPhilippe Charnier 		if (s < 0)
253c72049e4SPhilippe Charnier 			err(1, "socket");
254dea673e9SRodney W. Grimes 	}
255dea673e9SRodney W. Grimes }
256dea673e9SRodney W. Grimes 
257dea673e9SRodney W. Grimes /*
258dea673e9SRodney W. Grimes  * Set an individual arp entry
259dea673e9SRodney W. Grimes  */
260a42a667dSPoul-Henning Kamp int
261a42a667dSPoul-Henning Kamp set(int argc, char **argv)
262dea673e9SRodney W. Grimes {
263dea673e9SRodney W. Grimes 	struct hostent *hp;
2649d34414bSMike Heffner 	register struct sockaddr_inarp *addr = &sin_m;
265dea673e9SRodney W. Grimes 	register struct sockaddr_dl *sdl;
266dea673e9SRodney W. Grimes 	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
267a03b1b7cSRuslan Ermilov 	struct ether_addr *ea;
268dea673e9SRodney W. Grimes 	char *host = argv[0], *eaddr = argv[1];
269dea673e9SRodney W. Grimes 
270dea673e9SRodney W. Grimes 	getsocket();
271dea673e9SRodney W. Grimes 	argc -= 2;
272dea673e9SRodney W. Grimes 	argv += 2;
273dea673e9SRodney W. Grimes 	sdl_m = blank_sdl;
274dea673e9SRodney W. Grimes 	sin_m = blank_sin;
2759d34414bSMike Heffner 	addr->sin_addr.s_addr = inet_addr(host);
2769d34414bSMike Heffner 	if (addr->sin_addr.s_addr == INADDR_NONE) {
277dea673e9SRodney W. Grimes 		if (!(hp = gethostbyname(host))) {
278c72049e4SPhilippe Charnier 			warnx("%s: %s", host, hstrerror(h_errno));
279dea673e9SRodney W. Grimes 			return (1);
280dea673e9SRodney W. Grimes 		}
2819d34414bSMike Heffner 		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
2829d34414bSMike Heffner 		    sizeof addr->sin_addr);
283dea673e9SRodney W. Grimes 	}
2843f844a22SRuslan Ermilov 	doing_proxy = flags = proxy_only = expire_time = 0;
285dea673e9SRodney W. Grimes 	while (argc-- > 0) {
286dea673e9SRodney W. Grimes 		if (strncmp(argv[0], "temp", 4) == 0) {
2873f844a22SRuslan Ermilov 			struct timeval tv;
2883f844a22SRuslan Ermilov 			gettimeofday(&tv, 0);
2893f844a22SRuslan Ermilov 			expire_time = tv.tv_sec + 20 * 60;
290dea673e9SRodney W. Grimes 		}
291dea673e9SRodney W. Grimes 		else if (strncmp(argv[0], "pub", 3) == 0) {
292dea673e9SRodney W. Grimes 			flags |= RTF_ANNOUNCE;
2933f844a22SRuslan Ermilov 			doing_proxy = 1;
2943f844a22SRuslan Ermilov 			if (argc && strncmp(argv[1], "only", 3) == 0) {
2953f844a22SRuslan Ermilov 				proxy_only = 1;
2963f844a22SRuslan Ermilov 				sin_m.sin_other = SIN_PROXY;
2973f844a22SRuslan Ermilov 				argc--; argv++;
2983f844a22SRuslan Ermilov 			}
299dea673e9SRodney W. Grimes 		} else if (strncmp(argv[0], "trail", 5) == 0) {
300dea673e9SRodney W. Grimes 			printf("%s: Sending trailers is no longer supported\n",
301dea673e9SRodney W. Grimes 				host);
302dea673e9SRodney W. Grimes 		}
303dea673e9SRodney W. Grimes 		argv++;
304dea673e9SRodney W. Grimes 	}
305a03b1b7cSRuslan Ermilov 	ea = (struct ether_addr *)LLADDR(&sdl_m);
306a42a667dSPoul-Henning Kamp 	if (doing_proxy && !strcmp(eaddr, "auto")) {
3079d34414bSMike Heffner 		if (!get_ether_addr(addr->sin_addr.s_addr, ea)) {
308eec827b0SRuslan Ermilov 			printf("no interface found for %s\n",
3099d34414bSMike Heffner 			       inet_ntoa(addr->sin_addr));
310a42a667dSPoul-Henning Kamp 			return (1);
311a42a667dSPoul-Henning Kamp 		}
312a03b1b7cSRuslan Ermilov 		sdl_m.sdl_alen = ETHER_ADDR_LEN;
313a42a667dSPoul-Henning Kamp 	} else {
31463c64400SNate Williams 		if (my_ether_aton(eaddr, ea) == 0)
315a03b1b7cSRuslan Ermilov 			sdl_m.sdl_alen = ETHER_ADDR_LEN;
316a42a667dSPoul-Henning Kamp 	}
317dea673e9SRodney W. Grimes tryagain:
318dea673e9SRodney W. Grimes 	if (rtmsg(RTM_GET) < 0) {
319c72049e4SPhilippe Charnier 		warn("%s", host);
320dea673e9SRodney W. Grimes 		return (1);
321dea673e9SRodney W. Grimes 	}
3229d34414bSMike Heffner 	addr = (struct sockaddr_inarp *)(rtm + 1);
3239d34414bSMike Heffner 	sdl = (struct sockaddr_dl *)(ROUNDUP(addr->sin_len) + (char *)addr);
3249d34414bSMike Heffner 	if (addr->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
325dea673e9SRodney W. Grimes 		if (sdl->sdl_family == AF_LINK &&
326dea673e9SRodney W. Grimes 		    (rtm->rtm_flags & RTF_LLINFO) &&
327dea673e9SRodney W. Grimes 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
328dea673e9SRodney W. Grimes 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
32988d5b613SYaroslav Tykhiy 		case IFT_ISO88024: case IFT_ISO88025: case IFT_L2VLAN:
330dea673e9SRodney W. Grimes 			goto overwrite;
331dea673e9SRodney W. Grimes 		}
332dea673e9SRodney W. Grimes 		if (doing_proxy == 0) {
333dea673e9SRodney W. Grimes 			printf("set: can only proxy for %s\n", host);
334dea673e9SRodney W. Grimes 			return (1);
335dea673e9SRodney W. Grimes 		}
336dea673e9SRodney W. Grimes 		if (sin_m.sin_other & SIN_PROXY) {
337dea673e9SRodney W. Grimes 			printf("set: proxy entry exists for non 802 device\n");
338dea673e9SRodney W. Grimes 			return(1);
339dea673e9SRodney W. Grimes 		}
340dea673e9SRodney W. Grimes 		sin_m.sin_other = SIN_PROXY;
3413f844a22SRuslan Ermilov 		proxy_only = 1;
342dea673e9SRodney W. Grimes 		goto tryagain;
343dea673e9SRodney W. Grimes 	}
344dea673e9SRodney W. Grimes overwrite:
345dea673e9SRodney W. Grimes 	if (sdl->sdl_family != AF_LINK) {
346dea673e9SRodney W. Grimes 		printf("cannot intuit interface index and type for %s\n", host);
347dea673e9SRodney W. Grimes 		return (1);
348dea673e9SRodney W. Grimes 	}
349dea673e9SRodney W. Grimes 	sdl_m.sdl_type = sdl->sdl_type;
350dea673e9SRodney W. Grimes 	sdl_m.sdl_index = sdl->sdl_index;
351dea673e9SRodney W. Grimes 	return (rtmsg(RTM_ADD));
352dea673e9SRodney W. Grimes }
353dea673e9SRodney W. Grimes 
354dea673e9SRodney W. Grimes /*
355dea673e9SRodney W. Grimes  * Display an individual arp entry
356dea673e9SRodney W. Grimes  */
3578dc4b495SJulian Elischer int
358a42a667dSPoul-Henning Kamp get(char *host)
359dea673e9SRodney W. Grimes {
360dea673e9SRodney W. Grimes 	struct hostent *hp;
3619d34414bSMike Heffner 	struct sockaddr_inarp *addr = &sin_m;
362dea673e9SRodney W. Grimes 
363dea673e9SRodney W. Grimes 	sin_m = blank_sin;
3649d34414bSMike Heffner 	addr->sin_addr.s_addr = inet_addr(host);
3659d34414bSMike Heffner 	if (addr->sin_addr.s_addr == INADDR_NONE) {
366c72049e4SPhilippe Charnier 		if (!(hp = gethostbyname(host)))
367c72049e4SPhilippe Charnier 			errx(1, "%s: %s", host, hstrerror(h_errno));
3689d34414bSMike Heffner 		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
3699d34414bSMike Heffner 		    sizeof addr->sin_addr);
370dea673e9SRodney W. Grimes 	}
3719d34414bSMike Heffner 	search(addr->sin_addr.s_addr, print_entry);
372dea673e9SRodney W. Grimes 	if (found_entry == 0) {
373dea673e9SRodney W. Grimes 		printf("%s (%s) -- no entry\n",
3749d34414bSMike Heffner 		    host, inet_ntoa(addr->sin_addr));
3758dc4b495SJulian Elischer 		return(1);
376dea673e9SRodney W. Grimes 	}
3778dc4b495SJulian Elischer 	return(0);
378dea673e9SRodney W. Grimes }
379dea673e9SRodney W. Grimes 
380dea673e9SRodney W. Grimes /*
381dea673e9SRodney W. Grimes  * Delete an arp entry
382dea673e9SRodney W. Grimes  */
383a42a667dSPoul-Henning Kamp int
384a42a667dSPoul-Henning Kamp delete(char *host, char *info)
385dea673e9SRodney W. Grimes {
386dea673e9SRodney W. Grimes 	struct hostent *hp;
3879d34414bSMike Heffner 	register struct sockaddr_inarp *addr = &sin_m;
388dea673e9SRodney W. Grimes 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
389dea673e9SRodney W. Grimes 	struct sockaddr_dl *sdl;
390dea673e9SRodney W. Grimes 
391dea673e9SRodney W. Grimes 	getsocket();
392dea673e9SRodney W. Grimes 	sin_m = blank_sin;
3933f844a22SRuslan Ermilov 	if (info) {
3943f844a22SRuslan Ermilov 		if (strncmp(info, "pub", 3) == 0)
3959ea1ba64SRuslan Ermilov 			sin_m.sin_other = SIN_PROXY;
3963f844a22SRuslan Ermilov 		else
3973f844a22SRuslan Ermilov 			usage();
3983f844a22SRuslan Ermilov 	}
3999d34414bSMike Heffner 	addr->sin_addr.s_addr = inet_addr(host);
4009d34414bSMike Heffner 	if (addr->sin_addr.s_addr == INADDR_NONE) {
401dea673e9SRodney W. Grimes 		if (!(hp = gethostbyname(host))) {
402c72049e4SPhilippe Charnier 			warnx("%s: %s", host, hstrerror(h_errno));
403dea673e9SRodney W. Grimes 			return (1);
404dea673e9SRodney W. Grimes 		}
4059d34414bSMike Heffner 		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
4069d34414bSMike Heffner 		    sizeof addr->sin_addr);
407dea673e9SRodney W. Grimes 	}
408dea673e9SRodney W. Grimes tryagain:
409dea673e9SRodney W. Grimes 	if (rtmsg(RTM_GET) < 0) {
410c72049e4SPhilippe Charnier 		warn("%s", host);
411dea673e9SRodney W. Grimes 		return (1);
412dea673e9SRodney W. Grimes 	}
4139d34414bSMike Heffner 	addr = (struct sockaddr_inarp *)(rtm + 1);
4149d34414bSMike Heffner 	sdl = (struct sockaddr_dl *)(ROUNDUP(addr->sin_len) + (char *)addr);
4159d34414bSMike Heffner 	if (addr->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
416dea673e9SRodney W. Grimes 		if (sdl->sdl_family == AF_LINK &&
417dea673e9SRodney W. Grimes 		    (rtm->rtm_flags & RTF_LLINFO) &&
418dea673e9SRodney W. Grimes 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
419dea673e9SRodney W. Grimes 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
42088d5b613SYaroslav Tykhiy 		case IFT_ISO88024: case IFT_ISO88025: case IFT_L2VLAN:
421dea673e9SRodney W. Grimes 			goto delete;
422dea673e9SRodney W. Grimes 		}
423dea673e9SRodney W. Grimes 	}
424dea673e9SRodney W. Grimes 	if (sin_m.sin_other & SIN_PROXY) {
425dea673e9SRodney W. Grimes 		fprintf(stderr, "delete: can't locate %s\n",host);
426dea673e9SRodney W. Grimes 		return (1);
427dea673e9SRodney W. Grimes 	} else {
428dea673e9SRodney W. Grimes 		sin_m.sin_other = SIN_PROXY;
429dea673e9SRodney W. Grimes 		goto tryagain;
430dea673e9SRodney W. Grimes 	}
431dea673e9SRodney W. Grimes delete:
432dea673e9SRodney W. Grimes 	if (sdl->sdl_family != AF_LINK) {
433dea673e9SRodney W. Grimes 		printf("cannot locate %s\n", host);
434dea673e9SRodney W. Grimes 		return (1);
435dea673e9SRodney W. Grimes 	}
436a42a667dSPoul-Henning Kamp 	if (rtmsg(RTM_DELETE) == 0) {
4379d34414bSMike Heffner 		printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr));
438a42a667dSPoul-Henning Kamp 		return (0);
439a42a667dSPoul-Henning Kamp 	}
440a42a667dSPoul-Henning Kamp 	return (1);
441dea673e9SRodney W. Grimes }
442dea673e9SRodney W. Grimes 
443dea673e9SRodney W. Grimes /*
4448dc4b495SJulian Elischer  * Search the arp table and do some action on matching entries
445dea673e9SRodney W. Grimes  */
446a42a667dSPoul-Henning Kamp void
4478dc4b495SJulian Elischer search(u_long addr, void (*action)(struct sockaddr_dl *sdl,
4488dc4b495SJulian Elischer 	struct sockaddr_inarp *sin, struct rt_msghdr *rtm))
449dea673e9SRodney W. Grimes {
450dea673e9SRodney W. Grimes 	int mib[6];
451dea673e9SRodney W. Grimes 	size_t needed;
4528dc4b495SJulian Elischer 	char *lim, *buf, *next;
453dea673e9SRodney W. Grimes 	struct rt_msghdr *rtm;
4549d34414bSMike Heffner 	struct sockaddr_inarp *sin2;
455dea673e9SRodney W. Grimes 	struct sockaddr_dl *sdl;
456dea673e9SRodney W. Grimes 
457dea673e9SRodney W. Grimes 	mib[0] = CTL_NET;
458dea673e9SRodney W. Grimes 	mib[1] = PF_ROUTE;
459dea673e9SRodney W. Grimes 	mib[2] = 0;
460dea673e9SRodney W. Grimes 	mib[3] = AF_INET;
461dea673e9SRodney W. Grimes 	mib[4] = NET_RT_FLAGS;
462dea673e9SRodney W. Grimes 	mib[5] = RTF_LLINFO;
463dea673e9SRodney W. Grimes 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
464c72049e4SPhilippe Charnier 		errx(1, "route-sysctl-estimate");
465dea673e9SRodney W. Grimes 	if ((buf = malloc(needed)) == NULL)
466c72049e4SPhilippe Charnier 		errx(1, "malloc");
467dea673e9SRodney W. Grimes 	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
468c72049e4SPhilippe Charnier 		errx(1, "actual retrieval of routing table");
469dea673e9SRodney W. Grimes 	lim = buf + needed;
470dea673e9SRodney W. Grimes 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
471dea673e9SRodney W. Grimes 		rtm = (struct rt_msghdr *)next;
4729d34414bSMike Heffner 		sin2 = (struct sockaddr_inarp *)(rtm + 1);
4739d34414bSMike Heffner 		(char *)sdl = (char *)sin2 + ROUNDUP(sin2->sin_len);
474dea673e9SRodney W. Grimes 		if (addr) {
4759d34414bSMike Heffner 			if (addr != sin2->sin_addr.s_addr)
476dea673e9SRodney W. Grimes 				continue;
477dea673e9SRodney W. Grimes 			found_entry = 1;
478dea673e9SRodney W. Grimes 		}
4799d34414bSMike Heffner 		(*action)(sdl, sin2, rtm);
4808dc4b495SJulian Elischer 	}
481ae14be20SYaroslav Tykhiy 	free(buf);
4828dc4b495SJulian Elischer }
4838dc4b495SJulian Elischer 
4848dc4b495SJulian Elischer /*
4858dc4b495SJulian Elischer  * Display an arp entry
4868dc4b495SJulian Elischer  */
4878dc4b495SJulian Elischer void
4888dc4b495SJulian Elischer print_entry(struct sockaddr_dl *sdl,
4899d34414bSMike Heffner 	struct sockaddr_inarp *addr, struct rt_msghdr *rtm)
4908dc4b495SJulian Elischer {
4913f844a22SRuslan Ermilov 	const char *host;
4928dc4b495SJulian Elischer 	struct hostent *hp;
49397fe20b4SKelly Yancey 	struct iso88025_sockaddr_dl_data *trld;
494e87a372bSRuslan Ermilov 	char ifname[IF_NAMESIZE];
495fda82fc2SJulian Elischer 	int seg;
4968dc4b495SJulian Elischer 
497dea673e9SRodney W. Grimes 	if (nflag == 0)
4989d34414bSMike Heffner 		hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
4999d34414bSMike Heffner 		    sizeof addr->sin_addr, AF_INET);
500dea673e9SRodney W. Grimes 	else
501dea673e9SRodney W. Grimes 		hp = 0;
502dea673e9SRodney W. Grimes 	if (hp)
503dea673e9SRodney W. Grimes 		host = hp->h_name;
504dea673e9SRodney W. Grimes 	else {
505dea673e9SRodney W. Grimes 		host = "?";
506dea673e9SRodney W. Grimes 		if (h_errno == TRY_AGAIN)
507dea673e9SRodney W. Grimes 			nflag = 1;
508dea673e9SRodney W. Grimes 	}
5099d34414bSMike Heffner 	printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr));
510dea673e9SRodney W. Grimes 	if (sdl->sdl_alen)
511a03b1b7cSRuslan Ermilov 		printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl)));
512dea673e9SRodney W. Grimes 	else
513dea673e9SRodney W. Grimes 		printf("(incomplete)");
514e87a372bSRuslan Ermilov 	if (if_indextoname(sdl->sdl_index, ifname) != NULL)
515e87a372bSRuslan Ermilov 		printf(" on %s", ifname);
516dea673e9SRodney W. Grimes 	if (rtm->rtm_rmx.rmx_expire == 0)
517dea673e9SRodney W. Grimes 		printf(" permanent");
5189d34414bSMike Heffner 	if (addr->sin_other & SIN_PROXY)
519dea673e9SRodney W. Grimes 		printf(" published (proxy only)");
520dea673e9SRodney W. Grimes 	if (rtm->rtm_addrs & RTA_NETMASK) {
5219d34414bSMike Heffner 		addr = (struct sockaddr_inarp *)
5223a6a5ebeSRuslan Ermilov 			(ROUNDUP(sdl->sdl_len) + (char *)sdl);
5239d34414bSMike Heffner 		if (addr->sin_addr.s_addr == 0xffffffff)
524dea673e9SRodney W. Grimes 			printf(" published");
5259d34414bSMike Heffner 		if (addr->sin_len != 8)
5263a6a5ebeSRuslan Ermilov 			printf("(weird)");
527dea673e9SRodney W. Grimes 	}
528fda82fc2SJulian Elischer         switch(sdl->sdl_type) {
529fda82fc2SJulian Elischer             case IFT_ETHER:
530fda82fc2SJulian Elischer                 printf(" [ethernet]");
531fda82fc2SJulian Elischer                 break;
532fda82fc2SJulian Elischer             case IFT_ISO88025:
533fda82fc2SJulian Elischer                 printf(" [token-ring]");
53497fe20b4SKelly Yancey 		trld = SDL_ISO88025(sdl);
53597fe20b4SKelly Yancey 		if (trld->trld_rcf != 0) {
53697fe20b4SKelly Yancey 			printf(" rt=%x", ntohs(trld->trld_rcf));
53797fe20b4SKelly Yancey 			for (seg = 0;
53897fe20b4SKelly Yancey 			     seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2);
53997fe20b4SKelly Yancey 			     seg++)
54097fe20b4SKelly Yancey 				printf(":%x", ntohs(trld->trld_route[seg]));
54197fe20b4SKelly Yancey 		}
542fda82fc2SJulian Elischer                 break;
54304427472SMatthew N. Dodd             case IFT_FDDI:
54404427472SMatthew N. Dodd                 printf(" [fddi]");
54504427472SMatthew N. Dodd                 break;
54604427472SMatthew N. Dodd             case IFT_ATM:
54704427472SMatthew N. Dodd                 printf(" [atm]");
54804427472SMatthew N. Dodd                 break;
54988d5b613SYaroslav Tykhiy 	    case IFT_L2VLAN:
55088d5b613SYaroslav Tykhiy 		printf(" [vlan]");
55188d5b613SYaroslav Tykhiy 		break;
552fda82fc2SJulian Elischer             default:
553123b2d4aSMurray Stokely 		break;
554fda82fc2SJulian Elischer         }
555fda82fc2SJulian Elischer 
556dea673e9SRodney W. Grimes 	printf("\n");
557fda82fc2SJulian Elischer 
558dea673e9SRodney W. Grimes }
5598dc4b495SJulian Elischer 
5608dc4b495SJulian Elischer /*
5618dc4b495SJulian Elischer  * Nuke an arp entry
5628dc4b495SJulian Elischer  */
5638dc4b495SJulian Elischer void
5649d34414bSMike Heffner nuke_entry(struct sockaddr_dl *sdl __unused,
5659d34414bSMike Heffner 	struct sockaddr_inarp *addr, struct rt_msghdr *rtm __unused)
5668dc4b495SJulian Elischer {
5678dc4b495SJulian Elischer 	char ip[20];
5688dc4b495SJulian Elischer 
5699d34414bSMike Heffner 	snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr));
5708dc4b495SJulian Elischer 	delete(ip, NULL);
571dea673e9SRodney W. Grimes }
572dea673e9SRodney W. Grimes 
573a42a667dSPoul-Henning Kamp int
574a03b1b7cSRuslan Ermilov my_ether_aton(char *a, struct ether_addr *n)
575dea673e9SRodney W. Grimes {
576a03b1b7cSRuslan Ermilov 	struct ether_addr *ea;
577dea673e9SRodney W. Grimes 
578a03b1b7cSRuslan Ermilov 	if ((ea = ether_aton(a)) == NULL) {
579c72049e4SPhilippe Charnier 		warnx("invalid Ethernet address '%s'", a);
580dea673e9SRodney W. Grimes 		return (1);
581dea673e9SRodney W. Grimes 	}
582a03b1b7cSRuslan Ermilov 	*n = *ea;
583dea673e9SRodney W. Grimes 	return (0);
584dea673e9SRodney W. Grimes }
585dea673e9SRodney W. Grimes 
586a42a667dSPoul-Henning Kamp void
587a42a667dSPoul-Henning Kamp usage(void)
588dea673e9SRodney W. Grimes {
5898dc4b495SJulian Elischer 	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
590c72049e4SPhilippe Charnier 		"usage: arp [-n] hostname",
5918dc4b495SJulian Elischer 		"       arp [-n] -a",
5923f844a22SRuslan Ermilov 		"       arp -d hostname [pub]",
5938dc4b495SJulian Elischer 		"       arp -d -a",
594c72049e4SPhilippe Charnier 		"       arp -s hostname ether_addr [temp] [pub]",
595c72049e4SPhilippe Charnier 		"       arp -S hostname ether_addr [temp] [pub]",
596c72049e4SPhilippe Charnier 		"       arp -f filename");
597dea673e9SRodney W. Grimes 	exit(1);
598dea673e9SRodney W. Grimes }
599dea673e9SRodney W. Grimes 
600a42a667dSPoul-Henning Kamp int
601a42a667dSPoul-Henning Kamp rtmsg(int cmd)
602dea673e9SRodney W. Grimes {
603dea673e9SRodney W. Grimes 	static int seq;
604dea673e9SRodney W. Grimes 	int rlen;
605dea673e9SRodney W. Grimes 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
606dea673e9SRodney W. Grimes 	register char *cp = m_rtmsg.m_space;
607dea673e9SRodney W. Grimes 	register int l;
608dea673e9SRodney W. Grimes 
609dea673e9SRodney W. Grimes 	errno = 0;
610dea673e9SRodney W. Grimes 	if (cmd == RTM_DELETE)
611dea673e9SRodney W. Grimes 		goto doit;
612dea673e9SRodney W. Grimes 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
613dea673e9SRodney W. Grimes 	rtm->rtm_flags = flags;
614dea673e9SRodney W. Grimes 	rtm->rtm_version = RTM_VERSION;
615dea673e9SRodney W. Grimes 
616dea673e9SRodney W. Grimes 	switch (cmd) {
617dea673e9SRodney W. Grimes 	default:
618c72049e4SPhilippe Charnier 		errx(1, "internal wrong cmd");
619dea673e9SRodney W. Grimes 	case RTM_ADD:
620dea673e9SRodney W. Grimes 		rtm->rtm_addrs |= RTA_GATEWAY;
621dea673e9SRodney W. Grimes 		rtm->rtm_rmx.rmx_expire = expire_time;
622dea673e9SRodney W. Grimes 		rtm->rtm_inits = RTV_EXPIRE;
623dea673e9SRodney W. Grimes 		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
624dea673e9SRodney W. Grimes 		sin_m.sin_other = 0;
625dea673e9SRodney W. Grimes 		if (doing_proxy) {
6263f844a22SRuslan Ermilov 			if (proxy_only)
627dea673e9SRodney W. Grimes 				sin_m.sin_other = SIN_PROXY;
628dea673e9SRodney W. Grimes 			else {
629dea673e9SRodney W. Grimes 				rtm->rtm_addrs |= RTA_NETMASK;
630dea673e9SRodney W. Grimes 				rtm->rtm_flags &= ~RTF_HOST;
631dea673e9SRodney W. Grimes 			}
632dea673e9SRodney W. Grimes 		}
633dea673e9SRodney W. Grimes 		/* FALLTHROUGH */
634dea673e9SRodney W. Grimes 	case RTM_GET:
635dea673e9SRodney W. Grimes 		rtm->rtm_addrs |= RTA_DST;
636dea673e9SRodney W. Grimes 	}
637dea673e9SRodney W. Grimes #define NEXTADDR(w, s) \
638dea673e9SRodney W. Grimes 	if (rtm->rtm_addrs & (w)) { \
6393a6a5ebeSRuslan Ermilov 		bcopy((char *)&s, cp, sizeof(s)); cp += ROUNDUP(sizeof(s));}
640dea673e9SRodney W. Grimes 
641dea673e9SRodney W. Grimes 	NEXTADDR(RTA_DST, sin_m);
642dea673e9SRodney W. Grimes 	NEXTADDR(RTA_GATEWAY, sdl_m);
643dea673e9SRodney W. Grimes 	NEXTADDR(RTA_NETMASK, so_mask);
644dea673e9SRodney W. Grimes 
645dea673e9SRodney W. Grimes 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
646dea673e9SRodney W. Grimes doit:
647dea673e9SRodney W. Grimes 	l = rtm->rtm_msglen;
648dea673e9SRodney W. Grimes 	rtm->rtm_seq = ++seq;
649dea673e9SRodney W. Grimes 	rtm->rtm_type = cmd;
650dea673e9SRodney W. Grimes 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
651dea673e9SRodney W. Grimes 		if (errno != ESRCH || cmd != RTM_DELETE) {
652c72049e4SPhilippe Charnier 			warn("writing to routing socket");
653dea673e9SRodney W. Grimes 			return (-1);
654dea673e9SRodney W. Grimes 		}
655dea673e9SRodney W. Grimes 	}
656dea673e9SRodney W. Grimes 	do {
657dea673e9SRodney W. Grimes 		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
658dea673e9SRodney W. Grimes 	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
659dea673e9SRodney W. Grimes 	if (l < 0)
660c72049e4SPhilippe Charnier 		warn("read from routing socket");
661dea673e9SRodney W. Grimes 	return (0);
662dea673e9SRodney W. Grimes }
663dea673e9SRodney W. Grimes 
664a42a667dSPoul-Henning Kamp /*
665a42a667dSPoul-Henning Kamp  * get_ether_addr - get the hardware address of an interface on the
666a42a667dSPoul-Henning Kamp  * the same subnet as ipaddr.
667a42a667dSPoul-Henning Kamp  */
668a42a667dSPoul-Henning Kamp #define MAX_IFS		32
669a42a667dSPoul-Henning Kamp 
670a42a667dSPoul-Henning Kamp int
671a03b1b7cSRuslan Ermilov get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr)
672a42a667dSPoul-Henning Kamp {
673a42a667dSPoul-Henning Kamp 	struct ifreq *ifr, *ifend, *ifp;
6741fece1a6SYoshinobu Inoue 	u_int32_t ina, mask;
675a42a667dSPoul-Henning Kamp 	struct sockaddr_dl *dla;
676a42a667dSPoul-Henning Kamp 	struct ifreq ifreq;
677a42a667dSPoul-Henning Kamp 	struct ifconf ifc;
678a42a667dSPoul-Henning Kamp 	struct ifreq ifs[MAX_IFS];
6799d34414bSMike Heffner 	int sock;
680a42a667dSPoul-Henning Kamp 
6819d34414bSMike Heffner 	sock = socket(AF_INET, SOCK_DGRAM, 0);
6829d34414bSMike Heffner 	if (sock < 0)
683c72049e4SPhilippe Charnier 		err(1, "socket");
684a42a667dSPoul-Henning Kamp 
685a42a667dSPoul-Henning Kamp 	ifc.ifc_len = sizeof(ifs);
686a42a667dSPoul-Henning Kamp 	ifc.ifc_req = ifs;
6879cc7cb58SMike Heffner 	if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
688c72049e4SPhilippe Charnier 		warnx("ioctl(SIOCGIFCONF)");
6899d34414bSMike Heffner 		close(sock);
690a42a667dSPoul-Henning Kamp 		return 0;
691a42a667dSPoul-Henning Kamp 	}
692a42a667dSPoul-Henning Kamp 
693a42a667dSPoul-Henning Kamp 	/*
694a42a667dSPoul-Henning Kamp 	* Scan through looking for an interface with an Internet
695a42a667dSPoul-Henning Kamp 	* address on the same subnet as `ipaddr'.
696a42a667dSPoul-Henning Kamp 	*/
697a42a667dSPoul-Henning Kamp 	ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
698a42a667dSPoul-Henning Kamp 	for (ifr = ifc.ifc_req; ifr < ifend; ) {
699a42a667dSPoul-Henning Kamp 		if (ifr->ifr_addr.sa_family == AF_INET) {
700a42a667dSPoul-Henning Kamp 			ina = ((struct sockaddr_in *)
701a42a667dSPoul-Henning Kamp 				&ifr->ifr_addr)->sin_addr.s_addr;
702a42a667dSPoul-Henning Kamp 			strncpy(ifreq.ifr_name, ifr->ifr_name,
703a42a667dSPoul-Henning Kamp 				sizeof(ifreq.ifr_name));
704a42a667dSPoul-Henning Kamp 			/*
705a42a667dSPoul-Henning Kamp 			 * Check that the interface is up,
706a42a667dSPoul-Henning Kamp 			 * and not point-to-point or loopback.
707a42a667dSPoul-Henning Kamp 			 */
7089cc7cb58SMike Heffner 			if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0)
709a42a667dSPoul-Henning Kamp 				continue;
710a42a667dSPoul-Henning Kamp 			if ((ifreq.ifr_flags &
711a42a667dSPoul-Henning Kamp 			     (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
712a42a667dSPoul-Henning Kamp 					IFF_LOOPBACK|IFF_NOARP))
713a42a667dSPoul-Henning Kamp 			     != (IFF_UP|IFF_BROADCAST))
714a42a667dSPoul-Henning Kamp 				goto nextif;
715a42a667dSPoul-Henning Kamp 			/*
716a42a667dSPoul-Henning Kamp 			 * Get its netmask and check that it's on
717a42a667dSPoul-Henning Kamp 			 * the right subnet.
718a42a667dSPoul-Henning Kamp 			 */
7199cc7cb58SMike Heffner 			if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0)
720a42a667dSPoul-Henning Kamp 				continue;
721a42a667dSPoul-Henning Kamp 			mask = ((struct sockaddr_in *)
722a42a667dSPoul-Henning Kamp 				&ifreq.ifr_addr)->sin_addr.s_addr;
723a42a667dSPoul-Henning Kamp 			if ((ipaddr & mask) != (ina & mask))
724a42a667dSPoul-Henning Kamp 				goto nextif;
725a42a667dSPoul-Henning Kamp 			break;
726a42a667dSPoul-Henning Kamp 		}
727a42a667dSPoul-Henning Kamp nextif:
7283816c56cSArchie Cobbs 		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
7293816c56cSArchie Cobbs 		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
730a42a667dSPoul-Henning Kamp 	}
731a42a667dSPoul-Henning Kamp 
732a42a667dSPoul-Henning Kamp 	if (ifr >= ifend) {
7339d34414bSMike Heffner 		close(sock);
734a42a667dSPoul-Henning Kamp 		return 0;
735a42a667dSPoul-Henning Kamp 	}
736a42a667dSPoul-Henning Kamp 
737a42a667dSPoul-Henning Kamp 	/*
738a42a667dSPoul-Henning Kamp 	* Now scan through again looking for a link-level address
739a42a667dSPoul-Henning Kamp 	* for this interface.
740a42a667dSPoul-Henning Kamp 	*/
741a42a667dSPoul-Henning Kamp 	ifp = ifr;
742a42a667dSPoul-Henning Kamp 	for (ifr = ifc.ifc_req; ifr < ifend; ) {
743a42a667dSPoul-Henning Kamp 		if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
744a42a667dSPoul-Henning Kamp 		    && ifr->ifr_addr.sa_family == AF_LINK) {
745a42a667dSPoul-Henning Kamp 			/*
746a42a667dSPoul-Henning Kamp 			 * Found the link-level address - copy it out
747a42a667dSPoul-Henning Kamp 			 */
748a42a667dSPoul-Henning Kamp 		 	dla = (struct sockaddr_dl *) &ifr->ifr_addr;
749a42a667dSPoul-Henning Kamp 			memcpy(hwaddr,  LLADDR(dla), dla->sdl_alen);
7509cc7cb58SMike Heffner 			close (sock);
751a42a667dSPoul-Henning Kamp 			printf("using interface %s for proxy with address ",
752a42a667dSPoul-Henning Kamp 				ifp->ifr_name);
753a03b1b7cSRuslan Ermilov 			printf("%s\n", ether_ntoa(hwaddr));
754a42a667dSPoul-Henning Kamp 			return dla->sdl_alen;
755a42a667dSPoul-Henning Kamp 		}
7563816c56cSArchie Cobbs 		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
7573816c56cSArchie Cobbs 		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
758a42a667dSPoul-Henning Kamp 	}
759a42a667dSPoul-Henning Kamp 	return 0;
760a42a667dSPoul-Henning Kamp }
761