arp.c revision 128181
1/*
2 * Copyright (c) 1984, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Sun Microsystems, Inc.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#if 0
38#ifndef lint
39static char const copyright[] =
40"@(#) Copyright (c) 1984, 1993\n\
41	The Regents of the University of California.  All rights reserved.\n";
42#endif /* not lint */
43
44#ifndef lint
45static char const sccsid[] = "@(#)from: arp.c	8.2 (Berkeley) 1/2/94";
46#endif /* not lint */
47#endif
48#include <sys/cdefs.h>
49__FBSDID("$FreeBSD: head/usr.sbin/arp/arp.c 128181 2004-04-13 08:34:52Z luigi $");
50
51/*
52 * arp - display, set, and delete arp table entries
53 */
54
55
56#include <sys/param.h>
57#include <sys/file.h>
58#include <sys/socket.h>
59#include <sys/sockio.h>
60#include <sys/sysctl.h>
61#include <sys/ioctl.h>
62#include <sys/time.h>
63
64#include <net/if.h>
65#include <net/if_dl.h>
66#include <net/if_types.h>
67#include <net/route.h>
68#include <net/iso88025.h>
69
70#include <netinet/in.h>
71#include <netinet/if_ether.h>
72
73#include <arpa/inet.h>
74
75#include <ctype.h>
76#include <err.h>
77#include <errno.h>
78#include <netdb.h>
79#include <nlist.h>
80#include <paths.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <strings.h>
85#include <unistd.h>
86
87typedef void (action_fn)(struct sockaddr_dl *sdl,
88        struct sockaddr_inarp *s_in, struct rt_msghdr *rtm);
89
90static int search(u_long addr, action_fn *action);
91static action_fn print_entry;
92static action_fn nuke_entry;
93
94static int delete(char *host, char *info);
95static void usage(void);
96static int set(int argc, char **argv);
97static int get(char *host);
98static int file(char *name);
99static int my_ether_aton(char *a, struct ether_addr *n);
100static struct rt_msghdr *rtmsg(int cmd);
101static int get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr);
102
103static int nflag;	/* no reverse dns lookups */
104static char *rifname;
105
106static struct	sockaddr_inarp blank_sin, sin_m;
107static struct	sockaddr_dl sdl_m;
108static int	expire_time, flags, doing_proxy, proxy_only;
109/* which function we're supposed to do */
110#define F_GET		1
111#define F_SET		2
112#define F_FILESET	3
113#define F_REPLACE	4
114#define F_DELETE	5
115
116#define ROUNDUP(a) \
117	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
118#define SETFUNC(f)	{ if (func) usage(); func = (f); }
119
120int
121main(int argc, char *argv[])
122{
123	int ch, func = 0;
124	int rtn = 0;
125	int aflag = 0;	/* do it for all entries */
126
127	while ((ch = getopt(argc, argv, "andfsSi:")) != -1)
128		switch((char)ch) {
129		case 'a':
130			aflag = 1;
131			break;
132		case 'd':
133			SETFUNC(F_DELETE);
134			break;
135		case 'n':
136			nflag = 1;
137			break;
138		case 'S':
139			SETFUNC(F_REPLACE);
140			break;
141		case 's':
142			SETFUNC(F_SET);
143			break;
144		case 'f' :
145			SETFUNC(F_FILESET);
146			break;
147		case 'i':
148			rifname = optarg;
149			break;
150		case '?':
151		default:
152			usage();
153		}
154	argc -= optind;
155	argv += optind;
156
157	bzero(&blank_sin, sizeof(blank_sin));
158	blank_sin.sin_len = sizeof(blank_sin);
159	blank_sin.sin_family = AF_INET;
160
161	if (!func)
162		func = F_GET;
163	if (rifname) {
164		if (func != F_GET)
165			errx(1, "-i not applicable to this operation");
166		if (if_nametoindex(rifname) == 0) {
167			if (errno == ENXIO)
168				errx(1, "interface %s does not exist", rifname);
169			else
170				err(1, "if_nametoindex(%s)", rifname);
171		}
172	}
173	switch (func) {
174	case F_GET:
175		if (aflag) {
176			if (argc != 0)
177				usage();
178			search(0, print_entry);
179		} else {
180			if (argc != 1)
181				usage();
182			get(argv[0]);
183		}
184		break;
185	case F_SET:
186	case F_REPLACE:
187		if (argc < 2 || argc > 6)
188			usage();
189		if (func == F_REPLACE)
190			(void) delete(argv[0], NULL);
191		rtn = set(argc, argv) ? 1 : 0;
192		break;
193	case F_DELETE:
194		if (aflag) {
195			if (argc != 0)
196				usage();
197			search(0, nuke_entry);
198		} else {
199			if (argc < 1 || argc > 2)
200				usage();
201			rtn = delete(argv[0], argv[1]);
202		}
203		break;
204	case F_FILESET:
205		if (argc != 1)
206			usage();
207		rtn = file(argv[0]);
208		break;
209	}
210
211	return(rtn);
212}
213
214/*
215 * Process a file to set standard arp entries
216 */
217static int
218file(char *name)
219{
220	FILE *fp;
221	int i, retval;
222	char line[100], arg[5][50], *args[5], *p;
223
224	if ((fp = fopen(name, "r")) == NULL)
225		err(1, "cannot open %s", name);
226	args[0] = &arg[0][0];
227	args[1] = &arg[1][0];
228	args[2] = &arg[2][0];
229	args[3] = &arg[3][0];
230	args[4] = &arg[4][0];
231	retval = 0;
232	while(fgets(line, 100, fp) != NULL) {
233		if ((p = strchr(line, '#')) != NULL)
234			*p = '\0';
235		for (p = line; isblank(*p); p++);
236		if (*p == '\n' || *p == '\0')
237			continue;
238		i = sscanf(p, "%49s %49s %49s %49s %49s", arg[0], arg[1],
239		    arg[2], arg[3], arg[4]);
240		if (i < 2) {
241			warnx("bad line: %s", line);
242			retval = 1;
243			continue;
244		}
245		if (set(i, args))
246			retval = 1;
247	}
248	fclose(fp);
249	return (retval);
250}
251
252/*
253 * Set an individual arp entry
254 */
255int
256set(int argc, char **argv)
257{
258	struct hostent *hp;
259	struct sockaddr_inarp *addr = &sin_m;
260	struct sockaddr_dl *sdl;
261	struct rt_msghdr *rtm;
262	struct ether_addr *ea;
263	char *host = argv[0], *eaddr = argv[1];
264
265	argc -= 2;
266	argv += 2;
267
268	bzero(&sdl_m, sizeof(sdl_m));
269	sdl_m.sdl_len = sizeof(sdl_m);
270	sdl_m.sdl_family = AF_LINK;
271
272	sin_m = blank_sin;
273	addr->sin_addr.s_addr = inet_addr(host);
274	if (addr->sin_addr.s_addr == INADDR_NONE) {
275		if (!(hp = gethostbyname(host))) {
276			warnx("%s: %s", host, hstrerror(h_errno));
277			return (1);
278		}
279		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
280		    sizeof addr->sin_addr);
281	}
282	doing_proxy = flags = proxy_only = expire_time = 0;
283	while (argc-- > 0) {
284		if (strncmp(argv[0], "temp", 4) == 0) {
285			struct timeval tv;
286			gettimeofday(&tv, 0);
287			expire_time = tv.tv_sec + 20 * 60;
288		}
289		else if (strncmp(argv[0], "pub", 3) == 0) {
290			flags |= RTF_ANNOUNCE;
291			doing_proxy = 1;
292			if (argc && strncmp(argv[1], "only", 3) == 0) {
293				proxy_only = 1;
294				sin_m.sin_other = SIN_PROXY;
295				argc--; argv++;
296			}
297		} else if (strncmp(argv[0], "trail", 5) == 0) {
298			printf("%s: Sending trailers is no longer supported\n",
299				host);
300		}
301		argv++;
302	}
303	ea = (struct ether_addr *)LLADDR(&sdl_m);
304	if (doing_proxy && !strcmp(eaddr, "auto")) {
305		if (!get_ether_addr(addr->sin_addr.s_addr, ea)) {
306			printf("no interface found for %s\n",
307			       inet_ntoa(addr->sin_addr));
308			return (1);
309		}
310		sdl_m.sdl_alen = ETHER_ADDR_LEN;
311	} else {
312		if (my_ether_aton(eaddr, ea) == 0)
313			sdl_m.sdl_alen = ETHER_ADDR_LEN;
314	}
315tryagain:
316	rtm = rtmsg(RTM_GET);
317	if (rtm == NULL) {
318		warn("%s", host);
319		return (1);
320	}
321	addr = (struct sockaddr_inarp *)(rtm + 1);
322	sdl = (struct sockaddr_dl *)(ROUNDUP(addr->sin_len) + (char *)addr);
323	if (addr->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
324		if (sdl->sdl_family == AF_LINK &&
325		    (rtm->rtm_flags & RTF_LLINFO) &&
326		    !(rtm->rtm_flags & RTF_GATEWAY))
327			switch (sdl->sdl_type) {
328			case IFT_ETHER:
329			case IFT_FDDI:
330			case IFT_ISO88023:
331			case IFT_ISO88024:
332			case IFT_ISO88025:
333			case IFT_L2VLAN:
334				goto overwrite;
335			}
336		if (doing_proxy == 0) {
337			printf("set: can only proxy for %s\n", host);
338			return (1);
339		}
340		if (sin_m.sin_other & SIN_PROXY) {
341			printf("set: proxy entry exists for non 802 device\n");
342			return(1);
343		}
344		sin_m.sin_other = SIN_PROXY;
345		proxy_only = 1;
346		goto tryagain;
347	}
348overwrite:
349	if (sdl->sdl_family != AF_LINK) {
350		printf("cannot intuit interface index and type for %s\n", host);
351		return (1);
352	}
353	sdl_m.sdl_type = sdl->sdl_type;
354	sdl_m.sdl_index = sdl->sdl_index;
355	return (rtmsg(RTM_ADD) != NULL);
356}
357
358/*
359 * Display an individual arp entry
360 */
361static int
362get(char *host)
363{
364	struct hostent *hp;
365	struct sockaddr_inarp *addr = &sin_m;
366
367	sin_m = blank_sin;
368	addr->sin_addr.s_addr = inet_addr(host);
369	if (addr->sin_addr.s_addr == INADDR_NONE) {
370		if (!(hp = gethostbyname(host)))
371			errx(1, "%s: %s", host, hstrerror(h_errno));
372		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
373		    sizeof addr->sin_addr);
374	}
375	if (0 == search(addr->sin_addr.s_addr, print_entry)) {
376		printf("%s (%s) -- no entry",
377		    host, inet_ntoa(addr->sin_addr));
378		if (rifname)
379			printf(" on %s", rifname);
380		printf("\n");
381		return(1);
382	}
383	return(0);
384}
385
386/*
387 * Delete an arp entry
388 */
389static int
390delete(char *host, char *info)
391{
392	struct hostent *hp;
393	struct sockaddr_inarp *addr = &sin_m;
394	struct rt_msghdr *rtm;
395	struct sockaddr_dl *sdl;
396
397	sin_m = blank_sin;
398	if (info) {
399		if (strncmp(info, "pub", 3) == 0)
400			sin_m.sin_other = SIN_PROXY;
401		else
402			usage();
403	}
404	addr->sin_addr.s_addr = inet_addr(host);
405	if (addr->sin_addr.s_addr == INADDR_NONE) {
406		if (!(hp = gethostbyname(host))) {
407			warnx("%s: %s", host, hstrerror(h_errno));
408			return (1);
409		}
410		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
411		    sizeof addr->sin_addr);
412	}
413tryagain:
414	rtm = rtmsg(RTM_GET);
415	if (rtm == NULL) {
416		warn("%s", host);
417		return (1);
418	}
419	addr = (struct sockaddr_inarp *)(rtm + 1);
420	sdl = (struct sockaddr_dl *)(ROUNDUP(addr->sin_len) + (char *)addr);
421	if (addr->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
422		if (sdl->sdl_family == AF_LINK &&
423		    (rtm->rtm_flags & RTF_LLINFO) &&
424		    !(rtm->rtm_flags & RTF_GATEWAY))
425			switch (sdl->sdl_type) {
426			case IFT_ETHER:
427			case IFT_FDDI:
428			case IFT_ISO88023:
429			case IFT_ISO88024:
430			case IFT_ISO88025:
431			case IFT_L2VLAN:
432				goto delete;
433			}
434	}
435	if (sin_m.sin_other & SIN_PROXY) {
436		fprintf(stderr, "delete: can't locate %s\n",host);
437		return (1);
438	} else {
439		sin_m.sin_other = SIN_PROXY;
440		goto tryagain;
441	}
442delete:
443	if (sdl->sdl_family != AF_LINK) {
444		printf("cannot locate %s\n", host);
445		return (1);
446	}
447	if (rtmsg(RTM_DELETE) != NULL) {
448		printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr));
449		return (0);
450	}
451	return (1);
452}
453
454/*
455 * Search the arp table and do some action on matching entries
456 */
457static int
458search(u_long addr, action_fn *action)
459{
460	int mib[6];
461	size_t needed;
462	char *lim, *buf, *next;
463	struct rt_msghdr *rtm;
464	struct sockaddr_inarp *sin2;
465	struct sockaddr_dl *sdl;
466	char ifname[IF_NAMESIZE];
467	int found_entry = 0;
468
469	mib[0] = CTL_NET;
470	mib[1] = PF_ROUTE;
471	mib[2] = 0;
472	mib[3] = AF_INET;
473	mib[4] = NET_RT_FLAGS;
474	mib[5] = RTF_LLINFO;
475	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
476		err(1, "route-sysctl-estimate");
477	if (needed == 0)
478		return 0;
479	if ((buf = malloc(needed)) == NULL)
480		err(1, "malloc");
481	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
482		err(1, "actual retrieval of routing table");
483	lim = buf + needed;
484	for (next = buf; next < lim; next += rtm->rtm_msglen) {
485		rtm = (struct rt_msghdr *)next;
486		sin2 = (struct sockaddr_inarp *)(rtm + 1);
487		(char *)sdl = (char *)sin2 + ROUNDUP(sin2->sin_len);
488		if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
489		    strcmp(ifname, rifname))
490			continue;
491		if (addr) {
492			if (addr != sin2->sin_addr.s_addr)
493				continue;
494			found_entry = 1;
495		}
496		(*action)(sdl, sin2, rtm);
497	}
498	free(buf);
499	return found_entry;
500}
501
502/*
503 * Display an arp entry
504 */
505static void
506print_entry(struct sockaddr_dl *sdl,
507	struct sockaddr_inarp *addr, struct rt_msghdr *rtm)
508{
509	const char *host;
510	struct hostent *hp;
511	struct iso88025_sockaddr_dl_data *trld;
512	char ifname[IF_NAMESIZE];
513	int seg;
514
515	if (nflag == 0)
516		hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
517		    sizeof addr->sin_addr, AF_INET);
518	else
519		hp = 0;
520	if (hp)
521		host = hp->h_name;
522	else {
523		host = "?";
524		if (h_errno == TRY_AGAIN)
525			nflag = 1;
526	}
527	printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr));
528	if (sdl->sdl_alen)
529		printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl)));
530	else
531		printf("(incomplete)");
532	if (if_indextoname(sdl->sdl_index, ifname) != NULL)
533		printf(" on %s", ifname);
534	if (rtm->rtm_rmx.rmx_expire == 0)
535		printf(" permanent");
536	if (addr->sin_other & SIN_PROXY)
537		printf(" published (proxy only)");
538	if (rtm->rtm_addrs & RTA_NETMASK) {
539		addr = (struct sockaddr_inarp *)
540			(ROUNDUP(sdl->sdl_len) + (char *)sdl);
541		if (addr->sin_addr.s_addr == 0xffffffff)
542			printf(" published");
543		if (addr->sin_len != 8)
544			printf("(weird)");
545	}
546        switch(sdl->sdl_type) {
547	case IFT_ETHER:
548                printf(" [ethernet]");
549                break;
550	case IFT_ISO88025:
551                printf(" [token-ring]");
552		trld = SDL_ISO88025(sdl);
553		if (trld->trld_rcf != 0) {
554			printf(" rt=%x", ntohs(trld->trld_rcf));
555			for (seg = 0;
556			     seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2);
557			     seg++)
558				printf(":%x", ntohs(*(trld->trld_route[seg])));
559		}
560                break;
561	case IFT_FDDI:
562                printf(" [fddi]");
563                break;
564	case IFT_ATM:
565                printf(" [atm]");
566                break;
567	case IFT_L2VLAN:
568		printf(" [vlan]");
569		break;
570	default:
571		break;
572        }
573
574	printf("\n");
575
576}
577
578/*
579 * Nuke an arp entry
580 */
581static void
582nuke_entry(struct sockaddr_dl *sdl __unused,
583	struct sockaddr_inarp *addr, struct rt_msghdr *rtm __unused)
584{
585	char ip[20];
586
587	snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr));
588	delete(ip, NULL);
589}
590
591static int
592my_ether_aton(char *a, struct ether_addr *n)
593{
594	struct ether_addr *ea;
595
596	if ((ea = ether_aton(a)) == NULL) {
597		warnx("invalid Ethernet address '%s'", a);
598		return (1);
599	}
600	*n = *ea;
601	return (0);
602}
603
604static void
605usage(void)
606{
607	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
608		"usage: arp [-n] [-i interface] hostname",
609		"       arp [-n] [-i interface] -a",
610		"       arp -d hostname [pub]",
611		"       arp -d -a",
612		"       arp -s hostname ether_addr [temp] [pub]",
613		"       arp -S hostname ether_addr [temp] [pub]",
614		"       arp -f filename");
615	exit(1);
616}
617
618static struct rt_msghdr *
619rtmsg(int cmd)
620{
621	static int seq;
622	int rlen;
623	int l;
624	struct sockaddr_in so_mask;
625	static int s = -1;
626	static pid_t pid;
627
628	static struct	{
629		struct	rt_msghdr m_rtm;
630		char	m_space[512];
631	}	m_rtmsg;
632
633	struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
634	char *cp = m_rtmsg.m_space;
635
636	if (s < 0) {	/* first time: open socket, get pid */
637		s = socket(PF_ROUTE, SOCK_RAW, 0);
638		if (s < 0)
639			err(1, "socket");
640		pid = getpid();
641	}
642	bzero(&so_mask, sizeof(so_mask));
643	so_mask.sin_len = 8;
644	so_mask.sin_addr.s_addr = 0xffffffff;
645
646	errno = 0;
647	if (cmd == RTM_DELETE)
648		goto doit;
649	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
650	rtm->rtm_flags = flags;
651	rtm->rtm_version = RTM_VERSION;
652
653	switch (cmd) {
654	default:
655		errx(1, "internal wrong cmd");
656	case RTM_ADD:
657		rtm->rtm_addrs |= RTA_GATEWAY;
658		rtm->rtm_rmx.rmx_expire = expire_time;
659		rtm->rtm_inits = RTV_EXPIRE;
660		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
661		sin_m.sin_other = 0;
662		if (doing_proxy) {
663			if (proxy_only)
664				sin_m.sin_other = SIN_PROXY;
665			else {
666				rtm->rtm_addrs |= RTA_NETMASK;
667				rtm->rtm_flags &= ~RTF_HOST;
668			}
669		}
670		/* FALLTHROUGH */
671	case RTM_GET:
672		rtm->rtm_addrs |= RTA_DST;
673	}
674#define NEXTADDR(w, s) \
675	if (rtm->rtm_addrs & (w)) { \
676		bcopy((char *)&s, cp, sizeof(s)); cp += ROUNDUP(sizeof(s));}
677
678	NEXTADDR(RTA_DST, sin_m);
679	NEXTADDR(RTA_GATEWAY, sdl_m);
680	NEXTADDR(RTA_NETMASK, so_mask);
681
682	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
683doit:
684	l = rtm->rtm_msglen;
685	rtm->rtm_seq = ++seq;
686	rtm->rtm_type = cmd;
687	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
688		if (errno != ESRCH || cmd != RTM_DELETE) {
689			warn("writing to routing socket");
690			return NULL;
691		}
692	}
693	do {
694		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
695	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
696	if (l < 0)
697		warn("read from routing socket");
698	return rtm;
699}
700
701/*
702 * get_ether_addr - get the hardware address of an interface on the
703 * the same subnet as ipaddr.
704 */
705#define MAX_IFS		32
706
707static int
708get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr)
709{
710	struct ifreq *ifr, *ifend, *ifp;
711	u_int32_t ina, mask;
712	struct sockaddr_dl *dla;
713	struct ifreq ifreq;
714	struct ifconf ifc;
715	struct ifreq ifs[MAX_IFS];
716	int sock;
717
718	sock = socket(AF_INET, SOCK_DGRAM, 0);
719	if (sock < 0)
720		err(1, "socket");
721
722	ifc.ifc_len = sizeof(ifs);
723	ifc.ifc_req = ifs;
724	if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
725		warnx("ioctl(SIOCGIFCONF)");
726		close(sock);
727		return 0;
728	}
729
730	/*
731	* Scan through looking for an interface with an Internet
732	* address on the same subnet as `ipaddr'.
733	*/
734	ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
735	for (ifr = ifc.ifc_req; ifr < ifend; ) {
736		if (ifr->ifr_addr.sa_family == AF_INET) {
737			ina = ((struct sockaddr_in *)
738				&ifr->ifr_addr)->sin_addr.s_addr;
739			strncpy(ifreq.ifr_name, ifr->ifr_name,
740				sizeof(ifreq.ifr_name));
741			/*
742			 * Check that the interface is up,
743			 * and not point-to-point or loopback.
744			 */
745			if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0)
746				continue;
747			if ((ifreq.ifr_flags &
748			     (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
749					IFF_LOOPBACK|IFF_NOARP))
750			     != (IFF_UP|IFF_BROADCAST))
751				goto nextif;
752			/*
753			 * Get its netmask and check that it's on
754			 * the right subnet.
755			 */
756			if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0)
757				continue;
758			mask = ((struct sockaddr_in *)
759				&ifreq.ifr_addr)->sin_addr.s_addr;
760			if ((ipaddr & mask) != (ina & mask))
761				goto nextif;
762			break;
763		}
764nextif:
765		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
766		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
767	}
768
769	if (ifr >= ifend) {
770		close(sock);
771		return 0;
772	}
773
774	/*
775	* Now scan through again looking for a link-level address
776	* for this interface.
777	*/
778	ifp = ifr;
779	for (ifr = ifc.ifc_req; ifr < ifend; ) {
780		if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
781		    && ifr->ifr_addr.sa_family == AF_LINK) {
782			/*
783			 * Found the link-level address - copy it out
784			 */
785		 	dla = (struct sockaddr_dl *) &ifr->ifr_addr;
786			memcpy(hwaddr,  LLADDR(dla), dla->sdl_alen);
787			close (sock);
788			printf("using interface %s for proxy with address ",
789				ifp->ifr_name);
790			printf("%s\n", ether_ntoa(hwaddr));
791			return dla->sdl_alen;
792		}
793		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
794		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
795	}
796	return 0;
797}
798