arp.c revision 96202
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#ifndef lint
38static char const copyright[] =
39"@(#) Copyright (c) 1984, 1993\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44#if 0
45static char const sccsid[] = "@(#)from: arp.c	8.2 (Berkeley) 1/2/94";
46#endif
47static const char rcsid[] =
48  "$FreeBSD: head/usr.sbin/arp/arp.c 96202 2002-05-08 00:55:29Z kbyanc $";
49#endif /* not lint */
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/iso88025.h>
68#include <net/route.h>
69
70#include <netinet/in.h>
71#include <netinet/if_ether.h>
72
73#include <arpa/inet.h>
74
75#include <err.h>
76#include <errno.h>
77#include <netdb.h>
78#include <nlist.h>
79#include <paths.h>
80#include <stdio.h>
81#include <stdlib.h>
82#include <string.h>
83#include <strings.h>
84#include <unistd.h>
85
86void search(u_long addr, void (*action)(struct sockaddr_dl *sdl,
87	struct sockaddr_inarp *sin, struct rt_msghdr *rtm));
88void print_entry(struct sockaddr_dl *sdl,
89	struct sockaddr_inarp *addr, struct rt_msghdr *rtm);
90void nuke_entry(struct sockaddr_dl *sdl,
91	struct sockaddr_inarp *addr, struct rt_msghdr *rtm);
92int delete(char *host, char *info);
93void usage(void);
94int set(int argc, char **argv);
95int get(char *host);
96int file(char *name);
97void getsocket(void);
98int my_ether_aton(char *a, struct ether_addr *n);
99int rtmsg(int cmd);
100int get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr);
101
102static int pid;
103static int nflag;	/* no reverse dns lookups */
104static int aflag;	/* do it for all entries */
105static int s = -1;
106
107struct	sockaddr_in so_mask;
108struct	sockaddr_inarp blank_sin, sin_m;
109struct	sockaddr_dl blank_sdl, sdl_m;
110int	expire_time, flags, doing_proxy, proxy_only, found_entry;
111struct	{
112	struct	rt_msghdr m_rtm;
113	char	m_space[512];
114}	m_rtmsg;
115
116/* which function we're supposed to do */
117#define F_GET		1
118#define F_SET		2
119#define F_FILESET	3
120#define F_REPLACE	4
121#define F_DELETE	5
122
123#define ROUNDUP(a) \
124	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
125#define SETFUNC(f)	{ if (func) usage(); func = (f); }
126
127int
128main(int argc, char *argv[])
129{
130	int ch, func = 0;
131	int rtn = 0;
132
133	pid = getpid();
134	while ((ch = getopt(argc, argv, "andfsS")) != -1)
135		switch((char)ch) {
136		case 'a':
137			aflag = 1;
138			break;
139		case 'd':
140			SETFUNC(F_DELETE);
141			break;
142		case 'n':
143			nflag = 1;
144			break;
145		case 'S':
146			SETFUNC(F_REPLACE);
147			break;
148		case 's':
149			SETFUNC(F_SET);
150			break;
151		case 'f' :
152			SETFUNC(F_FILESET);
153			break;
154		case '?':
155		default:
156			usage();
157		}
158	argc -= optind;
159	argv += optind;
160
161	bzero(&so_mask, sizeof(so_mask));
162	so_mask.sin_len = 8;
163	so_mask.sin_addr.s_addr = 0xffffffff;
164	bzero(&blank_sin, sizeof(blank_sin));
165	blank_sin.sin_len = sizeof(blank_sin);
166	blank_sin.sin_family = AF_INET;
167	bzero(&blank_sdl, sizeof(blank_sdl));
168	blank_sdl.sdl_len = sizeof(blank_sdl);
169	blank_sdl.sdl_family = AF_LINK;
170
171	if (!func)
172		func = F_GET;
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 */
217int
218file(char *name)
219{
220	FILE *fp;
221	int i, retval;
222	char line[100], arg[5][50], *args[5];
223
224	if ((fp = fopen(name, "r")) == NULL)
225		errx(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		i = sscanf(line, "%49s %49s %49s %49s %49s", arg[0], arg[1],
234		    arg[2], arg[3], arg[4]);
235		if (i < 2) {
236			warnx("bad line: %s", line);
237			retval = 1;
238			continue;
239		}
240		if (set(i, args))
241			retval = 1;
242	}
243	fclose(fp);
244	return (retval);
245}
246
247void
248getsocket(void)
249{
250	if (s < 0) {
251		s = socket(PF_ROUTE, SOCK_RAW, 0);
252		if (s < 0)
253			err(1, "socket");
254	}
255}
256
257/*
258 * Set an individual arp entry
259 */
260int
261set(int argc, char **argv)
262{
263	struct hostent *hp;
264	register struct sockaddr_inarp *addr = &sin_m;
265	register struct sockaddr_dl *sdl;
266	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
267	struct ether_addr *ea;
268	char *host = argv[0], *eaddr = argv[1];
269
270	getsocket();
271	argc -= 2;
272	argv += 2;
273	sdl_m = blank_sdl;
274	sin_m = blank_sin;
275	addr->sin_addr.s_addr = inet_addr(host);
276	if (addr->sin_addr.s_addr == INADDR_NONE) {
277		if (!(hp = gethostbyname(host))) {
278			warnx("%s: %s", host, hstrerror(h_errno));
279			return (1);
280		}
281		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
282		    sizeof addr->sin_addr);
283	}
284	doing_proxy = flags = proxy_only = expire_time = 0;
285	while (argc-- > 0) {
286		if (strncmp(argv[0], "temp", 4) == 0) {
287			struct timeval tv;
288			gettimeofday(&tv, 0);
289			expire_time = tv.tv_sec + 20 * 60;
290		}
291		else if (strncmp(argv[0], "pub", 3) == 0) {
292			flags |= RTF_ANNOUNCE;
293			doing_proxy = 1;
294			if (argc && strncmp(argv[1], "only", 3) == 0) {
295				proxy_only = 1;
296				sin_m.sin_other = SIN_PROXY;
297				argc--; argv++;
298			}
299		} else if (strncmp(argv[0], "trail", 5) == 0) {
300			printf("%s: Sending trailers is no longer supported\n",
301				host);
302		}
303		argv++;
304	}
305	ea = (struct ether_addr *)LLADDR(&sdl_m);
306	if (doing_proxy && !strcmp(eaddr, "auto")) {
307		if (!get_ether_addr(addr->sin_addr.s_addr, ea)) {
308			printf("no interface found for %s\n",
309			       inet_ntoa(addr->sin_addr));
310			return (1);
311		}
312		sdl_m.sdl_alen = ETHER_ADDR_LEN;
313	} else {
314		if (my_ether_aton(eaddr, ea) == 0)
315			sdl_m.sdl_alen = ETHER_ADDR_LEN;
316	}
317tryagain:
318	if (rtmsg(RTM_GET) < 0) {
319		warn("%s", host);
320		return (1);
321	}
322	addr = (struct sockaddr_inarp *)(rtm + 1);
323	sdl = (struct sockaddr_dl *)(ROUNDUP(addr->sin_len) + (char *)addr);
324	if (addr->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
325		if (sdl->sdl_family == AF_LINK &&
326		    (rtm->rtm_flags & RTF_LLINFO) &&
327		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
328		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
329		case IFT_ISO88024: case IFT_ISO88025: case IFT_L2VLAN:
330			goto overwrite;
331		}
332		if (doing_proxy == 0) {
333			printf("set: can only proxy for %s\n", host);
334			return (1);
335		}
336		if (sin_m.sin_other & SIN_PROXY) {
337			printf("set: proxy entry exists for non 802 device\n");
338			return(1);
339		}
340		sin_m.sin_other = SIN_PROXY;
341		proxy_only = 1;
342		goto tryagain;
343	}
344overwrite:
345	if (sdl->sdl_family != AF_LINK) {
346		printf("cannot intuit interface index and type for %s\n", host);
347		return (1);
348	}
349	sdl_m.sdl_type = sdl->sdl_type;
350	sdl_m.sdl_index = sdl->sdl_index;
351	return (rtmsg(RTM_ADD));
352}
353
354/*
355 * Display an individual arp entry
356 */
357int
358get(char *host)
359{
360	struct hostent *hp;
361	struct sockaddr_inarp *addr = &sin_m;
362
363	sin_m = blank_sin;
364	addr->sin_addr.s_addr = inet_addr(host);
365	if (addr->sin_addr.s_addr == INADDR_NONE) {
366		if (!(hp = gethostbyname(host)))
367			errx(1, "%s: %s", host, hstrerror(h_errno));
368		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
369		    sizeof addr->sin_addr);
370	}
371	search(addr->sin_addr.s_addr, print_entry);
372	if (found_entry == 0) {
373		printf("%s (%s) -- no entry\n",
374		    host, inet_ntoa(addr->sin_addr));
375		return(1);
376	}
377	return(0);
378}
379
380/*
381 * Delete an arp entry
382 */
383int
384delete(char *host, char *info)
385{
386	struct hostent *hp;
387	register struct sockaddr_inarp *addr = &sin_m;
388	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
389	struct sockaddr_dl *sdl;
390
391	getsocket();
392	sin_m = blank_sin;
393	if (info) {
394		if (strncmp(info, "pub", 3) == 0)
395			sin_m.sin_other = SIN_PROXY;
396		else
397			usage();
398	}
399	addr->sin_addr.s_addr = inet_addr(host);
400	if (addr->sin_addr.s_addr == INADDR_NONE) {
401		if (!(hp = gethostbyname(host))) {
402			warnx("%s: %s", host, hstrerror(h_errno));
403			return (1);
404		}
405		bcopy((char *)hp->h_addr, (char *)&addr->sin_addr,
406		    sizeof addr->sin_addr);
407	}
408tryagain:
409	if (rtmsg(RTM_GET) < 0) {
410		warn("%s", host);
411		return (1);
412	}
413	addr = (struct sockaddr_inarp *)(rtm + 1);
414	sdl = (struct sockaddr_dl *)(ROUNDUP(addr->sin_len) + (char *)addr);
415	if (addr->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
416		if (sdl->sdl_family == AF_LINK &&
417		    (rtm->rtm_flags & RTF_LLINFO) &&
418		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
419		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
420		case IFT_ISO88024: case IFT_ISO88025: case IFT_L2VLAN:
421			goto delete;
422		}
423	}
424	if (sin_m.sin_other & SIN_PROXY) {
425		fprintf(stderr, "delete: can't locate %s\n",host);
426		return (1);
427	} else {
428		sin_m.sin_other = SIN_PROXY;
429		goto tryagain;
430	}
431delete:
432	if (sdl->sdl_family != AF_LINK) {
433		printf("cannot locate %s\n", host);
434		return (1);
435	}
436	if (rtmsg(RTM_DELETE) == 0) {
437		printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr));
438		return (0);
439	}
440	return (1);
441}
442
443/*
444 * Search the arp table and do some action on matching entries
445 */
446void
447search(u_long addr, void (*action)(struct sockaddr_dl *sdl,
448	struct sockaddr_inarp *sin, struct rt_msghdr *rtm))
449{
450	int mib[6];
451	size_t needed;
452	char *lim, *buf, *next;
453	struct rt_msghdr *rtm;
454	struct sockaddr_inarp *sin2;
455	struct sockaddr_dl *sdl;
456
457	mib[0] = CTL_NET;
458	mib[1] = PF_ROUTE;
459	mib[2] = 0;
460	mib[3] = AF_INET;
461	mib[4] = NET_RT_FLAGS;
462	mib[5] = RTF_LLINFO;
463	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
464		errx(1, "route-sysctl-estimate");
465	if ((buf = malloc(needed)) == NULL)
466		errx(1, "malloc");
467	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
468		errx(1, "actual retrieval of routing table");
469	lim = buf + needed;
470	for (next = buf; next < lim; next += rtm->rtm_msglen) {
471		rtm = (struct rt_msghdr *)next;
472		sin2 = (struct sockaddr_inarp *)(rtm + 1);
473		(char *)sdl = (char *)sin2 + ROUNDUP(sin2->sin_len);
474		if (addr) {
475			if (addr != sin2->sin_addr.s_addr)
476				continue;
477			found_entry = 1;
478		}
479		(*action)(sdl, sin2, rtm);
480	}
481	free(buf);
482}
483
484/*
485 * Display an arp entry
486 */
487void
488print_entry(struct sockaddr_dl *sdl,
489	struct sockaddr_inarp *addr, struct rt_msghdr *rtm)
490{
491	const char *host;
492	struct hostent *hp;
493	struct iso88025_sockaddr_dl_data *trld;
494	char ifname[IF_NAMESIZE];
495	int seg;
496
497	if (nflag == 0)
498		hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
499		    sizeof addr->sin_addr, AF_INET);
500	else
501		hp = 0;
502	if (hp)
503		host = hp->h_name;
504	else {
505		host = "?";
506		if (h_errno == TRY_AGAIN)
507			nflag = 1;
508	}
509	printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr));
510	if (sdl->sdl_alen)
511		printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl)));
512	else
513		printf("(incomplete)");
514	if (if_indextoname(sdl->sdl_index, ifname) != NULL)
515		printf(" on %s", ifname);
516	if (rtm->rtm_rmx.rmx_expire == 0)
517		printf(" permanent");
518	if (addr->sin_other & SIN_PROXY)
519		printf(" published (proxy only)");
520	if (rtm->rtm_addrs & RTA_NETMASK) {
521		addr = (struct sockaddr_inarp *)
522			(ROUNDUP(sdl->sdl_len) + (char *)sdl);
523		if (addr->sin_addr.s_addr == 0xffffffff)
524			printf(" published");
525		if (addr->sin_len != 8)
526			printf("(weird)");
527	}
528        switch(sdl->sdl_type) {
529            case IFT_ETHER:
530                printf(" [ethernet]");
531                break;
532            case IFT_ISO88025:
533                printf(" [token-ring]");
534		trld = SDL_ISO88025(sdl);
535		if (trld->trld_rcf != 0) {
536			printf(" rt=%x", ntohs(trld->trld_rcf));
537			for (seg = 0;
538			     seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2);
539			     seg++)
540				printf(":%x", ntohs(trld->trld_route[seg]));
541		}
542                break;
543            case IFT_FDDI:
544                printf(" [fddi]");
545                break;
546            case IFT_ATM:
547                printf(" [atm]");
548                break;
549	    case IFT_L2VLAN:
550		printf(" [vlan]");
551		break;
552            default:
553		break;
554        }
555
556	printf("\n");
557
558}
559
560/*
561 * Nuke an arp entry
562 */
563void
564nuke_entry(struct sockaddr_dl *sdl __unused,
565	struct sockaddr_inarp *addr, struct rt_msghdr *rtm __unused)
566{
567	char ip[20];
568
569	snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr));
570	delete(ip, NULL);
571}
572
573int
574my_ether_aton(char *a, struct ether_addr *n)
575{
576	struct ether_addr *ea;
577
578	if ((ea = ether_aton(a)) == NULL) {
579		warnx("invalid Ethernet address '%s'", a);
580		return (1);
581	}
582	*n = *ea;
583	return (0);
584}
585
586void
587usage(void)
588{
589	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
590		"usage: arp [-n] hostname",
591		"       arp [-n] -a",
592		"       arp -d hostname [pub]",
593		"       arp -d -a",
594		"       arp -s hostname ether_addr [temp] [pub]",
595		"       arp -S hostname ether_addr [temp] [pub]",
596		"       arp -f filename");
597	exit(1);
598}
599
600int
601rtmsg(int cmd)
602{
603	static int seq;
604	int rlen;
605	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
606	register char *cp = m_rtmsg.m_space;
607	register int l;
608
609	errno = 0;
610	if (cmd == RTM_DELETE)
611		goto doit;
612	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
613	rtm->rtm_flags = flags;
614	rtm->rtm_version = RTM_VERSION;
615
616	switch (cmd) {
617	default:
618		errx(1, "internal wrong cmd");
619	case RTM_ADD:
620		rtm->rtm_addrs |= RTA_GATEWAY;
621		rtm->rtm_rmx.rmx_expire = expire_time;
622		rtm->rtm_inits = RTV_EXPIRE;
623		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
624		sin_m.sin_other = 0;
625		if (doing_proxy) {
626			if (proxy_only)
627				sin_m.sin_other = SIN_PROXY;
628			else {
629				rtm->rtm_addrs |= RTA_NETMASK;
630				rtm->rtm_flags &= ~RTF_HOST;
631			}
632		}
633		/* FALLTHROUGH */
634	case RTM_GET:
635		rtm->rtm_addrs |= RTA_DST;
636	}
637#define NEXTADDR(w, s) \
638	if (rtm->rtm_addrs & (w)) { \
639		bcopy((char *)&s, cp, sizeof(s)); cp += ROUNDUP(sizeof(s));}
640
641	NEXTADDR(RTA_DST, sin_m);
642	NEXTADDR(RTA_GATEWAY, sdl_m);
643	NEXTADDR(RTA_NETMASK, so_mask);
644
645	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
646doit:
647	l = rtm->rtm_msglen;
648	rtm->rtm_seq = ++seq;
649	rtm->rtm_type = cmd;
650	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
651		if (errno != ESRCH || cmd != RTM_DELETE) {
652			warn("writing to routing socket");
653			return (-1);
654		}
655	}
656	do {
657		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
658	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
659	if (l < 0)
660		warn("read from routing socket");
661	return (0);
662}
663
664/*
665 * get_ether_addr - get the hardware address of an interface on the
666 * the same subnet as ipaddr.
667 */
668#define MAX_IFS		32
669
670int
671get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr)
672{
673	struct ifreq *ifr, *ifend, *ifp;
674	u_int32_t ina, mask;
675	struct sockaddr_dl *dla;
676	struct ifreq ifreq;
677	struct ifconf ifc;
678	struct ifreq ifs[MAX_IFS];
679	int sock;
680
681	sock = socket(AF_INET, SOCK_DGRAM, 0);
682	if (sock < 0)
683		err(1, "socket");
684
685	ifc.ifc_len = sizeof(ifs);
686	ifc.ifc_req = ifs;
687	if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
688		warnx("ioctl(SIOCGIFCONF)");
689		close(sock);
690		return 0;
691	}
692
693	/*
694	* Scan through looking for an interface with an Internet
695	* address on the same subnet as `ipaddr'.
696	*/
697	ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
698	for (ifr = ifc.ifc_req; ifr < ifend; ) {
699		if (ifr->ifr_addr.sa_family == AF_INET) {
700			ina = ((struct sockaddr_in *)
701				&ifr->ifr_addr)->sin_addr.s_addr;
702			strncpy(ifreq.ifr_name, ifr->ifr_name,
703				sizeof(ifreq.ifr_name));
704			/*
705			 * Check that the interface is up,
706			 * and not point-to-point or loopback.
707			 */
708			if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0)
709				continue;
710			if ((ifreq.ifr_flags &
711			     (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
712					IFF_LOOPBACK|IFF_NOARP))
713			     != (IFF_UP|IFF_BROADCAST))
714				goto nextif;
715			/*
716			 * Get its netmask and check that it's on
717			 * the right subnet.
718			 */
719			if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0)
720				continue;
721			mask = ((struct sockaddr_in *)
722				&ifreq.ifr_addr)->sin_addr.s_addr;
723			if ((ipaddr & mask) != (ina & mask))
724				goto nextif;
725			break;
726		}
727nextif:
728		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
729		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
730	}
731
732	if (ifr >= ifend) {
733		close(sock);
734		return 0;
735	}
736
737	/*
738	* Now scan through again looking for a link-level address
739	* for this interface.
740	*/
741	ifp = ifr;
742	for (ifr = ifc.ifc_req; ifr < ifend; ) {
743		if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
744		    && ifr->ifr_addr.sa_family == AF_LINK) {
745			/*
746			 * Found the link-level address - copy it out
747			 */
748		 	dla = (struct sockaddr_dl *) &ifr->ifr_addr;
749			memcpy(hwaddr,  LLADDR(dla), dla->sdl_alen);
750			close (sock);
751			printf("using interface %s for proxy with address ",
752				ifp->ifr_name);
753			printf("%s\n", ether_ntoa(hwaddr));
754			return dla->sdl_alen;
755		}
756		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
757		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
758	}
759	return 0;
760}
761