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