2 * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * Copyright (c) 1984, 1993
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software contributed to Berkeley by
34 * Sun Microsystems, Inc.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 static char const copyright
[] =
64 "@(#) Copyright (c) 1984, 1993\n\
65 The Regents of the University of California. All rights reserved.\n";
69 static char const sccsid
[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94";
71 #include <sys/cdefs.h>
72 __FBSDID("$FreeBSD: src/usr.sbin/arp/arp.c,v 1.65.2.1 2008/04/25 16:38:14 sam Exp $");
76 * arp - display, set, and delete arp table entries
80 #include <sys/param.h>
82 #include <sys/socket.h>
83 #include <sys/sockio.h>
84 #include <sys/sysctl.h>
85 #include <sys/ioctl.h>
89 #include <net/if_dl.h>
90 #include <net/if_types.h>
91 #include <net/route.h>
93 #include <net/iso88025.h>
96 #include <netinet/in.h>
97 #include <netinet/if_ether.h>
99 #include <arpa/inet.h>
113 typedef void (action_fn
)(struct sockaddr_dl
*sdl
,
114 struct sockaddr_inarp
*s_in
, struct rt_msghdr
*rtm
);
115 typedef void (action_ext_fn
)(struct sockaddr_dl
*sdl
,
116 struct sockaddr_inarp
*s_in
, struct rt_msghdr_ext
*rtm
);
118 static int search(in_addr_t addr
, action_fn
*action
);
119 static int search_ext(in_addr_t addr
, action_ext_fn
*action
);
120 static action_fn print_entry
;
121 static action_fn nuke_entry
;
122 static action_ext_fn print_entry_ext
;
124 static char *print_lladdr(struct sockaddr_dl
*);
125 static int delete(char *host
, int do_proxy
);
126 static void usage(void);
127 static int set(int argc
, char **argv
);
128 static int get(char *host
);
129 static int file(char *name
);
130 static struct rt_msghdr
*rtmsg(int cmd
,
131 struct sockaddr_inarp
*dst
, struct sockaddr_dl
*sdl
);
132 static int get_ether_addr(in_addr_t ipaddr
, struct ether_addr
*hwaddr
);
133 static struct sockaddr_inarp
*getaddr(char *host
);
134 static int valid_type(int type
);
135 static char *sec2str(time_t);
137 static int nflag
; /* no reverse dns lookups */
138 static int xflag
; /* extended link-layer reachability information */
139 static char *rifname
;
141 static int expire_time
, flags
, doing_proxy
, proxy_only
;
143 static char *boundif
= NULL
;
144 static unsigned int ifscope
= 0;
146 /* which function we're supposed to do */
154 #define SA_SIZE(sa) \
155 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
157 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
160 #define SETFUNC(f) { if (func) usage(); func = (f); }
164 main(int argc
, char *argv
[])
168 int aflag
= 0; /* do it for all entries */
170 uint32_t ifindex
= 0;
172 while ((ch
= getopt(argc
, argv
, "andflsSi:x")) != -1)
212 if (func
!= F_GET
&& !(func
== F_DELETE
&& aflag
))
213 errx(1, "-i not applicable to this operation");
214 if ((ifindex
= if_nametoindex(rifname
)) == 0) {
216 errx(1, "interface %s does not exist", rifname
);
218 err(1, "if_nametoindex(%s)", rifname
);
227 printf("%-23s %-17s %-9.9s %-9.9s %8.8s %4s "
229 "Linklayer Address", "Expire(O)",
230 "Expire(I)", "Netif", "Refs", "Prbs");
232 printf(" %-7.7s %-7.7s %-7.7s",
233 "RSSI", "LQM", "NPM");
235 search_ext(0, print_entry_ext
);
237 search(0, print_entry
);
247 if (argc
< 2 || argc
> 6)
249 if (func
== F_REPLACE
)
250 (void)delete(argv
[0], 0);
251 rtn
= set(argc
, argv
) ? 1 : 0;
257 search(0, nuke_entry
);
262 for (i
= 1; i
< argc
; i
++) {
263 if (strncmp(argv
[i
], "pub", sizeof("pub")) == 0) {
264 do_proxy
= SIN_PROXY
;
265 } else if (strncmp(argv
[i
], "ifscope", sizeof("ifscope")) == 0) {
267 printf("ifscope needs an interface parameter\n");
271 if ((ifscope
= if_nametoindex(boundif
)) == 0)
272 errx(1, "ifscope has bad interface name: %s", boundif
);
279 rtn
= delete(argv
[0], do_proxy
);
293 * Process a file to set standard arp entries
300 char line
[128], arg
[7][50], *args
[7], *p
;
302 if ((fp
= fopen(name
, "r")) == NULL
)
303 err(1, "cannot open %s", name
);
304 args
[0] = &arg
[0][0];
305 args
[1] = &arg
[1][0];
306 args
[2] = &arg
[2][0];
307 args
[3] = &arg
[3][0];
308 args
[4] = &arg
[4][0];
309 args
[5] = &arg
[5][0];
310 args
[6] = &arg
[6][0];
312 while(fgets(line
, sizeof(line
), fp
) != NULL
) {
313 if ((p
= strchr(line
, '#')) != NULL
)
315 for (p
= line
; isblank(*p
); p
++);
316 if (*p
== '\n' || *p
== '\0')
318 i
= sscanf(p
, "%49s %49s %49s %49s %49s %49s %49s", arg
[0], arg
[1],
319 arg
[2], arg
[3], arg
[4], arg
[5], arg
[6]);
321 warnx("bad line: %s", line
);
333 * Given a hostname, fills up a (static) struct sockaddr_inarp with
334 * the address of the host and returns a pointer to the
337 static struct sockaddr_inarp
*
341 static struct sockaddr_inarp reply
;
343 bzero(&reply
, sizeof(reply
));
344 reply
.sin_len
= sizeof(reply
);
345 reply
.sin_family
= AF_INET
;
346 reply
.sin_addr
.s_addr
= inet_addr(host
);
347 if (reply
.sin_addr
.s_addr
== INADDR_NONE
) {
348 if (!(hp
= gethostbyname(host
))) {
349 warnx("%s: %s", host
, hstrerror(h_errno
));
352 bcopy((char *)hp
->h_addr
, (char *)&reply
.sin_addr
,
353 sizeof reply
.sin_addr
);
359 * Returns true if the type is a valid one for ARP.
384 * Set an individual arp entry
387 set(int argc
, char **argv
)
389 struct sockaddr_inarp
*addr
;
390 struct sockaddr_inarp
*dst
; /* what are we looking for */
391 struct sockaddr_dl
*sdl
;
392 struct rt_msghdr
*rtm
;
393 struct ether_addr
*ea
;
394 char *host
= argv
[0], *eaddr
= argv
[1];
395 struct sockaddr_dl sdl_m
;
400 bzero(&sdl_m
, sizeof(sdl_m
));
401 sdl_m
.sdl_len
= sizeof(sdl_m
);
402 sdl_m
.sdl_family
= AF_LINK
;
407 doing_proxy
= flags
= proxy_only
= expire_time
= 0;
411 if (strncmp(argv
[0], "temp", sizeof("temp")) == 0) {
413 gettimeofday(&tv
, 0);
414 expire_time
= tv
.tv_sec
+ 20 * 60;
415 } else if (strncmp(argv
[0], "pub", sizeof("pub")) == 0) {
416 flags
|= RTF_ANNOUNCE
;
418 if (argc
&& strncmp(argv
[1], "only", sizeof("only")) == 0) {
420 dst
->sin_other
= SIN_PROXY
;
423 } else if (strncmp(argv
[0], "blackhole", sizeof("blackhole")) == 0) {
424 flags
|= RTF_BLACKHOLE
;
425 } else if (strncmp(argv
[0], "reject", sizeof("reject")) == 0) {
427 } else if (strncmp(argv
[0], "trail", sizeof("trail")) == 0) {
428 /* XXX deprecated and undocumented feature */
429 printf("%s: Sending trailers is no longer supported\n",
431 } else if (strncmp(argv
[0], "ifscope", sizeof("ifscope")) == 0) {
433 printf("ifscope needs an interface parameter\n");
437 if ((ifscope
= if_nametoindex(boundif
)) == 0)
438 errx(1, "ifscope has bad interface name: %s", boundif
);
443 ea
= (struct ether_addr
*)LLADDR(&sdl_m
);
444 if (doing_proxy
&& !strcmp(eaddr
, "auto")) {
445 if (!get_ether_addr(dst
->sin_addr
.s_addr
, ea
)) {
446 printf("no interface found for %s\n",
447 inet_ntoa(dst
->sin_addr
));
450 sdl_m
.sdl_alen
= ETHER_ADDR_LEN
;
452 struct ether_addr
*ea1
= ether_aton(eaddr
);
455 warnx("invalid Ethernet address '%s'", eaddr
);
459 sdl_m
.sdl_alen
= ETHER_ADDR_LEN
;
462 for (;;) { /* try at most twice */
463 rtm
= rtmsg(RTM_GET
, dst
, &sdl_m
);
468 addr
= (struct sockaddr_inarp
*)(rtm
+ 1);
469 sdl
= (struct sockaddr_dl
*)(SA_SIZE(addr
) + (char *)addr
);
470 if (addr
->sin_addr
.s_addr
!= dst
->sin_addr
.s_addr
)
472 if (sdl
->sdl_family
== AF_LINK
&&
473 (rtm
->rtm_flags
& RTF_LLINFO
) &&
474 !(rtm
->rtm_flags
& RTF_GATEWAY
) &&
475 valid_type(sdl
->sdl_type
) )
478 * If we asked for a scope entry and did not get one or
479 * did not asked for a scope entry and got one, we can
482 if ((ifscope
!= 0) != (rtm
->rtm_flags
& RTF_IFSCOPE
))
484 if (doing_proxy
== 0) {
485 printf("set: can only proxy for %s\n", host
);
488 if (dst
->sin_other
& SIN_PROXY
) {
489 printf("set: proxy entry exists for non 802 device\n");
492 dst
->sin_other
= SIN_PROXY
;
496 if (sdl
->sdl_family
!= AF_LINK
) {
497 printf("cannot intuit interface index and type for %s\n", host
);
500 sdl_m
.sdl_type
= sdl
->sdl_type
;
501 sdl_m
.sdl_index
= sdl
->sdl_index
;
502 return (rtmsg(RTM_ADD
, dst
, &sdl_m
) == NULL
);
506 * Display an individual arp entry
511 struct sockaddr_inarp
*addr
;
513 addr
= getaddr(host
);
516 if (0 == search(addr
->sin_addr
.s_addr
, print_entry
)) {
517 printf("%s (%s) -- no entry",
518 host
, inet_ntoa(addr
->sin_addr
));
520 printf(" on %s", rifname
);
528 * Delete an arp entry
531 delete(char *host
, int do_proxy
)
533 struct sockaddr_inarp
*addr
, *dst
;
534 struct rt_msghdr
*rtm
;
535 struct sockaddr_dl
*sdl
;
540 dst
->sin_other
= do_proxy
;
541 for (;;) { /* try twice */
542 rtm
= rtmsg(RTM_GET
, dst
, NULL
);
547 addr
= (struct sockaddr_inarp
*)(rtm
+ 1);
548 sdl
= (struct sockaddr_dl
*)(SA_SIZE(addr
) + (char *)addr
);
549 if (addr
->sin_addr
.s_addr
== dst
->sin_addr
.s_addr
&&
550 sdl
->sdl_family
== AF_LINK
&&
551 (rtm
->rtm_flags
& RTF_LLINFO
) &&
552 !(rtm
->rtm_flags
& RTF_GATEWAY
) &&
553 valid_type(sdl
->sdl_type
) )
554 break; /* found it */
555 if (dst
->sin_other
& SIN_PROXY
) {
556 fprintf(stderr
, "delete: cannot locate %s\n",host
);
559 dst
->sin_other
= SIN_PROXY
;
561 if (rtmsg(RTM_DELETE
, dst
, NULL
) != NULL
) {
562 printf("%s (%s) deleted\n", host
, inet_ntoa(addr
->sin_addr
));
569 * Search the arp table and do some action on matching entries
572 search(in_addr_t addr
, action_fn
*action
)
576 char *lim
, *buf
, *newbuf
, *next
;
577 struct rt_msghdr
*rtm
;
578 struct sockaddr_inarp
*sin2
;
579 struct sockaddr_dl
*sdl
;
580 char ifname
[IF_NAMESIZE
];
581 int st
, found_entry
= 0;
587 mib
[4] = NET_RT_FLAGS
;
589 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
590 err(1, "route-sysctl-estimate");
591 if (needed
== 0) /* empty table */
595 newbuf
= realloc(buf
, needed
);
596 if (newbuf
== NULL
) {
599 errx(1, "could not reallocate memory");
602 st
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
603 if (st
== 0 || errno
!= ENOMEM
)
605 needed
+= needed
/ 8;
608 err(1, "actual retrieval of routing table");
610 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
611 rtm
= (struct rt_msghdr
*)next
;
612 sin2
= (struct sockaddr_inarp
*)(rtm
+ 1);
613 sdl
= (struct sockaddr_dl
*)((char *)sin2
+ SA_SIZE(sin2
));
614 if (rifname
&& if_indextoname(sdl
->sdl_index
, ifname
) &&
615 strcmp(ifname
, rifname
))
618 if (addr
!= sin2
->sin_addr
.s_addr
)
622 (*action
)(sdl
, sin2
, rtm
);
625 return (found_entry
);
629 * Stolen and adapted from ifconfig
632 print_lladdr(struct sockaddr_dl
*sdl
)
634 static char buf
[256];
636 int n
, bufsize
= sizeof (buf
), p
= 0;
638 bzero(buf
, sizeof (buf
));
639 cp
= (char *)LLADDR(sdl
);
640 if ((n
= sdl
->sdl_alen
) > 0) {
642 p
+= snprintf(buf
+ p
, bufsize
- p
, "%x%s",
643 *cp
++ & 0xff, n
> 0 ? ":" : "");
649 * Display an arp entry
652 print_entry(struct sockaddr_dl
*sdl
,
653 struct sockaddr_inarp
*addr
, struct rt_msghdr
*rtm
)
657 char ifname
[IF_NAMESIZE
];
659 struct iso88025_sockaddr_dl_data
*trld
;
664 hp
= gethostbyaddr((caddr_t
)&(addr
->sin_addr
),
665 sizeof addr
->sin_addr
, AF_INET
);
672 if (h_errno
== TRY_AGAIN
)
675 printf("%s (%s) at ", host
, inet_ntoa(addr
->sin_addr
));
678 printf("%s", print_lladdr(sdl
));
680 if ((sdl
->sdl_type
== IFT_ETHER
||
681 sdl
->sdl_type
== IFT_L2VLAN
||
682 sdl
->sdl_type
== IFT_BRIDGE
) &&
683 sdl
->sdl_alen
== ETHER_ADDR_LEN
)
684 printf("%s", ether_ntoa((struct ether_addr
*)LLADDR(sdl
)));
686 int n
= sdl
->sdl_nlen
> 0 ? sdl
->sdl_nlen
+ 1 : 0;
688 printf("%s", link_ntoa(sdl
) + n
);
692 printf("(incomplete)");
693 if (if_indextoname(sdl
->sdl_index
, ifname
) != NULL
)
694 printf(" on %s", ifname
);
695 if ((rtm
->rtm_flags
& RTF_IFSCOPE
))
697 if (rtm
->rtm_rmx
.rmx_expire
== 0)
698 printf(" permanent");
699 if (addr
->sin_other
& SIN_PROXY
)
700 printf(" published (proxy only)");
701 if (rtm
->rtm_addrs
& RTA_NETMASK
) {
702 addr
= (struct sockaddr_inarp
*)
703 (SA_SIZE(sdl
) + (char *)sdl
);
704 if (addr
->sin_addr
.s_addr
== 0xffffffff)
705 printf(" published");
706 if (addr
->sin_len
!= 8)
709 switch(sdl
->sdl_type
) {
711 printf(" [ethernet]");
715 printf(" [token-ring]");
716 trld
= SDL_ISO88025(sdl
);
717 if (trld
->trld_rcf
!= 0) {
718 printf(" rt=%x", ntohs(trld
->trld_rcf
));
720 seg
< ((TR_RCF_RIFLEN(trld
->trld_rcf
) - 2 ) / 2);
722 printf(":%x", ntohs(*(trld
->trld_route
[seg
])));
736 printf(" [firewire]");
755 nuke_entry(struct sockaddr_dl
*sdl __unused
,
756 struct sockaddr_inarp
*addr
, struct rt_msghdr
*rtm
)
760 snprintf(ip
, sizeof(ip
), "%s", inet_ntoa(addr
->sin_addr
));
762 * When deleting all entries, specify the interface scope of each entry
764 if ((rtm
->rtm_flags
& RTF_IFSCOPE
))
765 ifscope
= rtm
->rtm_index
;
773 fprintf(stderr
, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
774 "usage: arp [-n] [-i interface] hostname",
775 " arp [-n] [-i interface] [-l] -a",
776 " arp -d hostname [pub] [ifscope interface]",
777 " arp -d [-i interface] -a",
778 " arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
779 " arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
784 static struct rt_msghdr
*
785 rtmsg(int cmd
, struct sockaddr_inarp
*dst
, struct sockaddr_dl
*sdl
)
790 struct sockaddr_in so_mask
, *so_mask_ptr
= &so_mask
;
795 struct rt_msghdr m_rtm
;
799 struct rt_msghdr
*rtm
= &m_rtmsg
.m_rtm
;
800 char *cp
= m_rtmsg
.m_space
;
802 if (s
< 0) { /* first time: open socket, get pid */
803 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
808 bzero(&so_mask
, sizeof(so_mask
));
810 so_mask
.sin_addr
.s_addr
= 0xffffffff;
814 * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer
815 * appropriately (except for the mask set just above).
817 if (cmd
== RTM_DELETE
)
819 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
820 rtm
->rtm_flags
= flags
;
821 rtm
->rtm_version
= RTM_VERSION
;
824 * Note: On RTM_GET the kernel will return a scoped route when both a scoped route and
825 * a unscoped route exist. That means we cannot delete a unscoped route if there is
826 * also a matching scope route
829 rtm
->rtm_index
= ifscope
;
830 rtm
->rtm_flags
|= RTF_IFSCOPE
;
835 errx(1, "internal wrong cmd");
837 rtm
->rtm_addrs
|= RTA_GATEWAY
;
838 rtm
->rtm_rmx
.rmx_expire
= expire_time
;
839 rtm
->rtm_inits
= RTV_EXPIRE
;
840 rtm
->rtm_flags
|= (RTF_HOST
| RTF_STATIC
);
844 dst
->sin_other
= SIN_PROXY
;
846 rtm
->rtm_addrs
|= RTA_NETMASK
;
847 rtm
->rtm_flags
&= ~RTF_HOST
;
852 rtm
->rtm_addrs
|= RTA_DST
;
854 #define NEXTADDR(w, s) \
855 if ((s) != NULL && rtm->rtm_addrs & (w)) { \
856 bcopy((s), cp, sizeof(*(s))); cp += SA_SIZE(s);}
858 NEXTADDR(RTA_DST
, dst
);
859 NEXTADDR(RTA_GATEWAY
, sdl
);
860 NEXTADDR(RTA_NETMASK
, so_mask_ptr
);
862 rtm
->rtm_msglen
= cp
- (char *)&m_rtmsg
;
865 rtm
->rtm_seq
= ++seq
;
867 if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
868 if (errno
!= ESRCH
|| cmd
!= RTM_DELETE
) {
869 warn("writing to routing socket");
874 l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
875 } while (l
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= pid
));
877 warn("read from routing socket");
882 * get_ether_addr - get the hardware address of an interface on the
883 * the same subnet as ipaddr.
888 get_ether_addr(in_addr_t ipaddr
, struct ether_addr
*hwaddr
)
890 struct ifreq
*ifr
, *ifend
, *ifp
;
892 struct sockaddr_dl
*dla
;
895 struct ifreq ifs
[MAX_IFS
];
899 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
903 ifc
.ifc_len
= sizeof(ifs
);
905 if (ioctl(sock
, SIOCGIFCONF
, &ifc
) < 0) {
906 warnx("ioctl(SIOCGIFCONF)");
911 ((struct ifreq *)((char *)&(i)->ifr_addr \
912 + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) )
915 * Scan through looking for an interface with an Internet
916 * address on the same subnet as `ipaddr'.
918 ifend
= (struct ifreq
*)(ifc
.ifc_buf
+ ifc
.ifc_len
);
919 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= NEXTIFR(ifr
) ) {
920 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
922 strncpy(ifreq
.ifr_name
, ifr
->ifr_name
,
923 sizeof(ifreq
.ifr_name
));
924 ifreq
.ifr_addr
= ifr
->ifr_addr
;
926 * Check that the interface is up,
927 * and not point-to-point or loopback.
929 if (ioctl(sock
, SIOCGIFFLAGS
, &ifreq
) < 0)
931 if ((ifreq
.ifr_flags
&
932 (IFF_UP
|IFF_BROADCAST
|IFF_POINTOPOINT
|
933 IFF_LOOPBACK
|IFF_NOARP
))
934 != (IFF_UP
|IFF_BROADCAST
))
937 * Get its netmask and check that it's on
940 if (ioctl(sock
, SIOCGIFNETMASK
, &ifreq
) < 0)
942 mask
= ((struct sockaddr_in
*)
943 &ifreq
.ifr_addr
)->sin_addr
.s_addr
;
944 ina
= ((struct sockaddr_in
*)
945 &ifr
->ifr_addr
)->sin_addr
.s_addr
;
946 if ((ipaddr
& mask
) == (ina
& mask
))
947 break; /* ok, we got it! */
954 * Now scan through again looking for a link-level address
955 * for this interface.
958 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= NEXTIFR(ifr
))
959 if (strcmp(ifp
->ifr_name
, ifr
->ifr_name
) == 0 &&
960 ifr
->ifr_addr
.sa_family
== AF_LINK
)
965 * Found the link-level address - copy it out
967 dla
= (struct sockaddr_dl
*) &ifr
->ifr_addr
;
968 memcpy(hwaddr
, LLADDR(dla
), dla
->sdl_alen
);
969 printf("using interface %s for proxy with address ",
971 printf("%s\n", ether_ntoa(hwaddr
));
972 retval
= dla
->sdl_alen
;
982 static char result
[256];
983 int days
, hours
, mins
, secs
;
987 days
= total
/ 3600 / 24;
988 hours
= (total
/ 3600) % 24;
989 mins
= (total
/ 60) % 60;
994 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dd", days
);
996 if (!first
|| hours
) {
998 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dh", hours
);
1000 if (!first
|| mins
) {
1002 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dm", mins
);
1004 snprintf(p
, sizeof(result
) - (p
- result
), "%ds", secs
);
1010 search_ext(in_addr_t addr
, action_ext_fn
*action
)
1014 char *lim
, *buf
, *newbuf
, *next
;
1015 struct rt_msghdr_ext
*ertm
;
1016 struct sockaddr_inarp
*sin2
;
1017 struct sockaddr_dl
*sdl
;
1018 char ifname
[IF_NAMESIZE
];
1019 int st
, found_entry
= 0;
1025 mib
[4] = NET_RT_DUMPX_FLAGS
;
1026 mib
[5] = RTF_LLINFO
;
1027 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1028 err(1, "route-sysctl-estimate");
1029 if (needed
== 0) /* empty table */
1033 newbuf
= realloc(buf
, needed
);
1034 if (newbuf
== NULL
) {
1037 errx(1, "could not reallocate memory");
1040 st
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
1041 if (st
== 0 || errno
!= ENOMEM
)
1043 needed
+= needed
/ 8;
1046 err(1, "actual retrieval of routing table");
1048 for (next
= buf
; next
< lim
; next
+= ertm
->rtm_msglen
) {
1049 ertm
= (struct rt_msghdr_ext
*)next
;
1050 sin2
= (struct sockaddr_inarp
*)(ertm
+ 1);
1051 sdl
= (struct sockaddr_dl
*)((char *)sin2
+ SA_SIZE(sin2
));
1052 if (rifname
&& if_indextoname(sdl
->sdl_index
, ifname
) &&
1053 strcmp(ifname
, rifname
))
1056 if (addr
!= sin2
->sin_addr
.s_addr
)
1060 (*action
)(sdl
, sin2
, ertm
);
1063 return (found_entry
);
1067 print_entry_ext(struct sockaddr_dl
*sdl
, struct sockaddr_inarp
*addr
,
1068 struct rt_msghdr_ext
*ertm
)
1072 char ifname
[IF_NAMESIZE
];
1073 struct timeval time
;
1076 hp
= gethostbyaddr((caddr_t
)&(addr
->sin_addr
),
1077 sizeof (addr
->sin_addr
), AF_INET
);
1084 host
= inet_ntoa(addr
->sin_addr
);
1086 printf("%-23s ", host
);
1089 printf("%-17s ", print_lladdr(sdl
));
1091 printf("%-17s ", "(incomplete)");
1093 gettimeofday(&time
, 0);
1095 if (ertm
->rtm_ri
.ri_refcnt
== 0 || ertm
->rtm_ri
.ri_snd_expire
== 0)
1096 printf("%-9.9s ", "(none)");
1097 else if (ertm
->rtm_ri
.ri_snd_expire
> time
.tv_sec
)
1099 sec2str(ertm
->rtm_ri
.ri_snd_expire
- time
.tv_sec
));
1101 printf("%-9.9s ", "expired");
1103 if (ertm
->rtm_ri
.ri_refcnt
== 0 || ertm
->rtm_ri
.ri_rcv_expire
== 0)
1104 printf("%-9.9s", "(none)");
1105 else if (ertm
->rtm_ri
.ri_rcv_expire
> time
.tv_sec
)
1107 sec2str(ertm
->rtm_ri
.ri_rcv_expire
- time
.tv_sec
));
1109 printf("%-9.9s", "expired");
1111 if (if_indextoname(sdl
->sdl_index
, ifname
) == NULL
)
1112 snprintf(ifname
, sizeof (ifname
), "%s", "?");
1113 printf(" %8.8s", ifname
);
1115 if (ertm
->rtm_ri
.ri_refcnt
) {
1116 printf(" %4d", ertm
->rtm_ri
.ri_refcnt
);
1117 if (ertm
->rtm_ri
.ri_probes
)
1118 printf(" %4d", ertm
->rtm_ri
.ri_probes
);
1121 if (!ertm
->rtm_ri
.ri_probes
)
1122 printf(" %-4.4s", "none");
1124 if (ertm
->rtm_ri
.ri_rssi
!= IFNET_RSSI_UNKNOWN
)
1125 printf(" %7d", ertm
->rtm_ri
.ri_rssi
);
1127 printf(" %-7.7s", "unknown");
1129 switch (ertm
->rtm_ri
.ri_lqm
)
1131 case IFNET_LQM_THRESH_OFF
:
1132 printf(" %-7.7s", "off");
1134 case IFNET_LQM_THRESH_UNKNOWN
:
1135 printf(" %-7.7s", "unknown");
1137 case IFNET_LQM_THRESH_POOR
:
1138 printf(" %-7.7s", "poor");
1140 case IFNET_LQM_THRESH_GOOD
:
1141 printf(" %-7.7s", "good");
1144 printf(" %7d", ertm
->rtm_ri
.ri_lqm
);
1148 switch (ertm
->rtm_ri
.ri_npm
)
1150 case IFNET_NPM_THRESH_UNKNOWN
:
1151 printf(" %-7.7s", "unknown");
1153 case IFNET_NPM_THRESH_NEAR
:
1154 printf(" %-7.7s", "near");
1156 case IFNET_NPM_THRESH_GENERAL
:
1157 printf(" %-7.7s", "general");
1159 case IFNET_NPM_THRESH_FAR
:
1160 printf(" %-7.7s", "far");
1163 printf(" %7d", ertm
->rtm_ri
.ri_npm
);