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";
70 * arp - display, set, and delete arp table entries
74 #include <sys/param.h>
76 #include <sys/socket.h>
77 #include <sys/sockio.h>
78 #include <sys/sysctl.h>
79 #include <sys/ioctl.h>
83 #include <net/if_dl.h>
84 #include <net/if_types.h>
85 #include <net/route.h>
87 #include <net/iso88025.h>
90 #include <netinet/in.h>
91 #include <netinet/if_ether.h>
93 #include <arpa/inet.h>
107 typedef void (action_fn
)(struct sockaddr_dl
*sdl
,
108 struct sockaddr_inarp
*s_in
, struct rt_msghdr
*rtm
);
109 typedef void (action_ext_fn
)(struct sockaddr_dl
*sdl
,
110 struct sockaddr_inarp
*s_in
, struct rt_msghdr_ext
*rtm
);
112 static int search(in_addr_t addr
, action_fn
*action
);
113 static int search_ext(in_addr_t addr
, action_ext_fn
*action
);
114 static action_fn print_entry
;
115 static action_fn nuke_entry
;
116 static action_ext_fn print_entry_ext
;
118 static char *print_lladdr(struct sockaddr_dl
*);
119 static int delete(char *host
, int do_proxy
);
120 static void usage(void);
121 static int set(int argc
, char **argv
);
122 static int get(char *host
);
123 static int file(char *name
);
124 static struct rt_msghdr
*rtmsg(int cmd
,
125 struct sockaddr_inarp
*dst
, struct sockaddr_dl
*sdl
);
126 static int get_ether_addr(in_addr_t ipaddr
, struct ether_addr
*hwaddr
);
127 static struct sockaddr_inarp
*getaddr(char *host
);
128 static int valid_type(int type
);
129 static char *sec2str(time_t);
131 static int nflag
; /* no reverse dns lookups */
132 static int xflag
; /* extended link-layer reachability information */
133 static char *rifname
;
135 static int expire_time
, flags
, doing_proxy
, proxy_only
;
137 static char *boundif
= NULL
;
138 static unsigned int ifscope
= 0;
140 /* which function we're supposed to do */
148 #define SA_SIZE(sa) \
149 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
151 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
154 #define SETFUNC(f) { if (func) usage(); func = (f); }
158 main(int argc
, char *argv
[])
162 int aflag
= 0; /* do it for all entries */
164 uint32_t ifindex
= 0;
166 while ((ch
= getopt(argc
, argv
, "andflsSi:x")) != -1)
206 if (func
!= F_GET
&& !(func
== F_DELETE
&& aflag
))
207 errx(1, "-i not applicable to this operation");
208 if ((ifindex
= if_nametoindex(rifname
)) == 0) {
210 errx(1, "interface %s does not exist", rifname
);
212 err(1, "if_nametoindex(%s)", rifname
);
221 printf("%-23s %-17s %-9.9s %-9.9s %8.8s %4s "
223 "Linklayer Address", "Expire(O)",
224 "Expire(I)", "Netif", "Refs", "Prbs");
226 printf(" %-7.7s %-7.7s %-7.7s",
227 "RSSI", "LQM", "NPM");
229 search_ext(0, print_entry_ext
);
231 search(0, print_entry
);
241 if (argc
< 2 || argc
> 6)
243 if (func
== F_REPLACE
)
244 (void)delete(argv
[0], 0);
245 rtn
= set(argc
, argv
) ? 1 : 0;
251 search(0, nuke_entry
);
256 for (i
= 1; i
< argc
; i
++) {
257 if (strncmp(argv
[i
], "pub", sizeof("pub")) == 0) {
258 do_proxy
= SIN_PROXY
;
259 } else if (strncmp(argv
[i
], "ifscope", sizeof("ifscope")) == 0) {
261 printf("ifscope needs an interface parameter\n");
265 if ((ifscope
= if_nametoindex(boundif
)) == 0)
266 errx(1, "ifscope has bad interface name: %s", boundif
);
273 rtn
= delete(argv
[0], do_proxy
);
287 * Process a file to set standard arp entries
294 char line
[128], arg
[7][50], *args
[7], *p
;
296 if ((fp
= fopen(name
, "r")) == NULL
)
297 err(1, "cannot open %s", name
);
298 args
[0] = &arg
[0][0];
299 args
[1] = &arg
[1][0];
300 args
[2] = &arg
[2][0];
301 args
[3] = &arg
[3][0];
302 args
[4] = &arg
[4][0];
303 args
[5] = &arg
[5][0];
304 args
[6] = &arg
[6][0];
306 while(fgets(line
, sizeof(line
), fp
) != NULL
) {
307 if ((p
= strchr(line
, '#')) != NULL
)
309 for (p
= line
; isblank(*p
); p
++);
310 if (*p
== '\n' || *p
== '\0')
312 i
= sscanf(p
, "%49s %49s %49s %49s %49s %49s %49s", arg
[0], arg
[1],
313 arg
[2], arg
[3], arg
[4], arg
[5], arg
[6]);
315 warnx("bad line: %s", line
);
327 * Given a hostname, fills up a (static) struct sockaddr_inarp with
328 * the address of the host and returns a pointer to the
331 static struct sockaddr_inarp
*
335 static struct sockaddr_inarp reply
;
337 bzero(&reply
, sizeof(reply
));
338 reply
.sin_len
= sizeof(reply
);
339 reply
.sin_family
= AF_INET
;
340 reply
.sin_addr
.s_addr
= inet_addr(host
);
341 if (reply
.sin_addr
.s_addr
== INADDR_NONE
) {
342 if (!(hp
= gethostbyname(host
))) {
343 warnx("%s: %s", host
, hstrerror(h_errno
));
346 bcopy((char *)hp
->h_addr
, (char *)&reply
.sin_addr
,
347 sizeof reply
.sin_addr
);
353 * Returns true if the type is a valid one for ARP.
378 * Set an individual arp entry
381 set(int argc
, char **argv
)
383 struct sockaddr_inarp
*addr
;
384 struct sockaddr_inarp
*dst
; /* what are we looking for */
385 struct sockaddr_dl
*sdl
;
386 struct rt_msghdr
*rtm
;
387 struct ether_addr
*ea
;
388 char *host
= argv
[0], *eaddr
= argv
[1];
389 struct sockaddr_dl sdl_m
;
394 bzero(&sdl_m
, sizeof(sdl_m
));
395 sdl_m
.sdl_len
= sizeof(sdl_m
);
396 sdl_m
.sdl_family
= AF_LINK
;
401 doing_proxy
= flags
= proxy_only
= expire_time
= 0;
405 if (strncmp(argv
[0], "temp", sizeof("temp")) == 0) {
407 gettimeofday(&tv
, 0);
408 expire_time
= tv
.tv_sec
+ 20 * 60;
409 } else if (strncmp(argv
[0], "pub", sizeof("pub")) == 0) {
410 flags
|= RTF_ANNOUNCE
;
412 if (argc
&& strncmp(argv
[1], "only", sizeof("only")) == 0) {
414 dst
->sin_other
= SIN_PROXY
;
417 } else if (strncmp(argv
[0], "blackhole", sizeof("blackhole")) == 0) {
418 flags
|= RTF_BLACKHOLE
;
419 } else if (strncmp(argv
[0], "reject", sizeof("reject")) == 0) {
421 } else if (strncmp(argv
[0], "trail", sizeof("trail")) == 0) {
422 /* XXX deprecated and undocumented feature */
423 printf("%s: Sending trailers is no longer supported\n",
425 } else if (strncmp(argv
[0], "ifscope", sizeof("ifscope")) == 0) {
427 printf("ifscope needs an interface parameter\n");
431 if ((ifscope
= if_nametoindex(boundif
)) == 0)
432 errx(1, "ifscope has bad interface name: %s", boundif
);
437 ea
= (struct ether_addr
*)LLADDR(&sdl_m
);
438 if (doing_proxy
&& !strcmp(eaddr
, "auto")) {
439 if (!get_ether_addr(dst
->sin_addr
.s_addr
, ea
)) {
440 printf("no interface found for %s\n",
441 inet_ntoa(dst
->sin_addr
));
444 sdl_m
.sdl_alen
= ETHER_ADDR_LEN
;
446 struct ether_addr
*ea1
= ether_aton(eaddr
);
449 warnx("invalid Ethernet address '%s'", eaddr
);
453 sdl_m
.sdl_alen
= ETHER_ADDR_LEN
;
456 for (;;) { /* try at most twice */
457 rtm
= rtmsg(RTM_GET
, dst
, &sdl_m
);
462 addr
= (struct sockaddr_inarp
*)(rtm
+ 1);
463 sdl
= (struct sockaddr_dl
*)(SA_SIZE(addr
) + (char *)addr
);
464 if (addr
->sin_addr
.s_addr
!= dst
->sin_addr
.s_addr
)
466 if (sdl
->sdl_family
== AF_LINK
&&
467 (rtm
->rtm_flags
& RTF_LLINFO
) &&
468 !(rtm
->rtm_flags
& RTF_GATEWAY
) &&
469 valid_type(sdl
->sdl_type
) )
472 * If we asked for a scope entry and did not get one or
473 * did not asked for a scope entry and got one, we can
476 if ((ifscope
!= 0) != (rtm
->rtm_flags
& RTF_IFSCOPE
))
478 if (doing_proxy
== 0) {
479 printf("set: can only proxy for %s\n", host
);
482 if (dst
->sin_other
& SIN_PROXY
) {
483 printf("set: proxy entry exists for non 802 device\n");
486 dst
->sin_other
= SIN_PROXY
;
490 if (sdl
->sdl_family
!= AF_LINK
) {
491 printf("cannot intuit interface index and type for %s\n", host
);
494 sdl_m
.sdl_type
= sdl
->sdl_type
;
495 sdl_m
.sdl_index
= sdl
->sdl_index
;
496 return (rtmsg(RTM_ADD
, dst
, &sdl_m
) == NULL
);
500 * Display an individual arp entry
505 struct sockaddr_inarp
*addr
;
507 addr
= getaddr(host
);
510 if (0 == search(addr
->sin_addr
.s_addr
, print_entry
)) {
511 printf("%s (%s) -- no entry",
512 host
, inet_ntoa(addr
->sin_addr
));
514 printf(" on %s", rifname
);
522 * Delete an arp entry
525 delete(char *host
, int do_proxy
)
527 struct sockaddr_inarp
*addr
, *dst
;
528 struct rt_msghdr
*rtm
;
529 struct sockaddr_dl
*sdl
;
534 dst
->sin_other
= do_proxy
;
535 for (;;) { /* try twice */
536 rtm
= rtmsg(RTM_GET
, dst
, NULL
);
541 addr
= (struct sockaddr_inarp
*)(rtm
+ 1);
542 sdl
= (struct sockaddr_dl
*)(SA_SIZE(addr
) + (char *)addr
);
543 if (addr
->sin_addr
.s_addr
== dst
->sin_addr
.s_addr
&&
544 sdl
->sdl_family
== AF_LINK
&&
545 (rtm
->rtm_flags
& RTF_LLINFO
) &&
546 !(rtm
->rtm_flags
& RTF_GATEWAY
) &&
547 valid_type(sdl
->sdl_type
) )
548 break; /* found it */
549 if (dst
->sin_other
& SIN_PROXY
) {
550 fprintf(stderr
, "delete: cannot locate %s\n",host
);
553 dst
->sin_other
= SIN_PROXY
;
555 if (rtmsg(RTM_DELETE
, dst
, NULL
) != NULL
) {
556 printf("%s (%s) deleted\n", host
, inet_ntoa(addr
->sin_addr
));
563 * Search the arp table and do some action on matching entries
566 search(in_addr_t addr
, action_fn
*action
)
570 char *lim
, *buf
, *newbuf
, *next
;
571 struct rt_msghdr
*rtm
;
572 struct sockaddr_inarp
*sin2
;
573 struct sockaddr_dl
*sdl
;
574 char ifname
[IF_NAMESIZE
];
575 int st
, found_entry
= 0;
581 mib
[4] = NET_RT_FLAGS
;
583 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
584 err(1, "route-sysctl-estimate");
585 if (needed
== 0) /* empty table */
589 newbuf
= realloc(buf
, needed
);
590 if (newbuf
== NULL
) {
593 errx(1, "could not reallocate memory");
596 st
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
597 if (st
== 0 || errno
!= ENOMEM
)
599 needed
+= needed
/ 8;
602 err(1, "actual retrieval of routing table");
604 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
605 rtm
= (struct rt_msghdr
*)next
;
606 sin2
= (struct sockaddr_inarp
*)(rtm
+ 1);
607 sdl
= (struct sockaddr_dl
*)((char *)sin2
+ SA_SIZE(sin2
));
608 if (rifname
&& if_indextoname(sdl
->sdl_index
, ifname
) &&
609 strcmp(ifname
, rifname
))
612 if (addr
!= sin2
->sin_addr
.s_addr
)
616 (*action
)(sdl
, sin2
, rtm
);
619 return (found_entry
);
623 * Stolen and adapted from ifconfig
626 print_lladdr(struct sockaddr_dl
*sdl
)
628 static char buf
[256];
630 int n
, bufsize
= sizeof (buf
), p
= 0;
632 bzero(buf
, sizeof (buf
));
633 cp
= (char *)LLADDR(sdl
);
634 if ((n
= sdl
->sdl_alen
) > 0) {
636 p
+= snprintf(buf
+ p
, bufsize
- p
, "%x%s",
637 *cp
++ & 0xff, n
> 0 ? ":" : "");
643 * Display an arp entry
646 print_entry(struct sockaddr_dl
*sdl
,
647 struct sockaddr_inarp
*addr
, struct rt_msghdr
*rtm
)
651 char ifname
[IF_NAMESIZE
];
653 struct iso88025_sockaddr_dl_data
*trld
;
658 hp
= gethostbyaddr((caddr_t
)&(addr
->sin_addr
),
659 sizeof addr
->sin_addr
, AF_INET
);
666 if (h_errno
== TRY_AGAIN
)
669 printf("%s (%s) at ", host
, inet_ntoa(addr
->sin_addr
));
672 printf("%s", print_lladdr(sdl
));
674 if ((sdl
->sdl_type
== IFT_ETHER
||
675 sdl
->sdl_type
== IFT_L2VLAN
||
676 sdl
->sdl_type
== IFT_BRIDGE
) &&
677 sdl
->sdl_alen
== ETHER_ADDR_LEN
)
678 printf("%s", ether_ntoa((struct ether_addr
*)LLADDR(sdl
)));
680 int n
= sdl
->sdl_nlen
> 0 ? sdl
->sdl_nlen
+ 1 : 0;
682 printf("%s", link_ntoa(sdl
) + n
);
686 printf("(incomplete)");
687 if (if_indextoname(sdl
->sdl_index
, ifname
) != NULL
)
688 printf(" on %s", ifname
);
689 if ((rtm
->rtm_flags
& RTF_IFSCOPE
))
691 if (rtm
->rtm_rmx
.rmx_expire
== 0)
692 printf(" permanent");
693 if (addr
->sin_other
& SIN_PROXY
)
694 printf(" published (proxy only)");
695 if (rtm
->rtm_addrs
& RTA_NETMASK
) {
696 addr
= (struct sockaddr_inarp
*)
697 (SA_SIZE(sdl
) + (char *)sdl
);
698 if (addr
->sin_addr
.s_addr
== 0xffffffff)
699 printf(" published");
700 if (addr
->sin_len
!= 8)
703 switch(sdl
->sdl_type
) {
705 printf(" [ethernet]");
709 printf(" [token-ring]");
710 trld
= SDL_ISO88025(sdl
);
711 if (trld
->trld_rcf
!= 0) {
712 printf(" rt=%x", ntohs(trld
->trld_rcf
));
714 seg
< ((TR_RCF_RIFLEN(trld
->trld_rcf
) - 2 ) / 2);
716 printf(":%x", ntohs(*(trld
->trld_route
[seg
])));
730 printf(" [firewire]");
749 nuke_entry(struct sockaddr_dl
*sdl __unused
,
750 struct sockaddr_inarp
*addr
, struct rt_msghdr
*rtm
)
754 snprintf(ip
, sizeof(ip
), "%s", inet_ntoa(addr
->sin_addr
));
756 * When deleting all entries, specify the interface scope of each entry
758 if ((rtm
->rtm_flags
& RTF_IFSCOPE
))
759 ifscope
= rtm
->rtm_index
;
767 fprintf(stderr
, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
768 "usage: arp [-n] [-i interface] hostname",
769 " arp [-n] [-i interface] [-l] -a",
770 " arp -d hostname [pub] [ifscope interface]",
771 " arp -d [-i interface] -a",
772 " arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
773 " arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
778 static struct rt_msghdr
*
779 rtmsg(int cmd
, struct sockaddr_inarp
*dst
, struct sockaddr_dl
*sdl
)
784 struct sockaddr_in so_mask
, *so_mask_ptr
= &so_mask
;
789 struct rt_msghdr m_rtm
;
793 struct rt_msghdr
*rtm
= &m_rtmsg
.m_rtm
;
794 char *cp
= m_rtmsg
.m_space
;
796 if (s
< 0) { /* first time: open socket, get pid */
797 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
802 bzero(&so_mask
, sizeof(so_mask
));
804 so_mask
.sin_addr
.s_addr
= 0xffffffff;
808 * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer
809 * appropriately (except for the mask set just above).
811 if (cmd
== RTM_DELETE
)
813 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
814 rtm
->rtm_flags
= flags
;
815 rtm
->rtm_version
= RTM_VERSION
;
818 * Note: On RTM_GET the kernel will return a scoped route when both a scoped route and
819 * a unscoped route exist. That means we cannot delete a unscoped route if there is
820 * also a matching scope route
823 rtm
->rtm_index
= ifscope
;
824 rtm
->rtm_flags
|= RTF_IFSCOPE
;
829 errx(1, "internal wrong cmd");
831 rtm
->rtm_addrs
|= RTA_GATEWAY
;
832 rtm
->rtm_rmx
.rmx_expire
= expire_time
;
833 rtm
->rtm_inits
= RTV_EXPIRE
;
834 rtm
->rtm_flags
|= (RTF_HOST
| RTF_STATIC
);
838 dst
->sin_other
= SIN_PROXY
;
840 rtm
->rtm_addrs
|= RTA_NETMASK
;
841 rtm
->rtm_flags
&= ~RTF_HOST
;
846 rtm
->rtm_addrs
|= RTA_DST
;
848 #define NEXTADDR(w, s) \
849 if ((s) != NULL && rtm->rtm_addrs & (w)) { \
850 bcopy((s), cp, sizeof(*(s))); cp += SA_SIZE(s);}
852 NEXTADDR(RTA_DST
, dst
);
853 NEXTADDR(RTA_GATEWAY
, sdl
);
854 NEXTADDR(RTA_NETMASK
, so_mask_ptr
);
856 rtm
->rtm_msglen
= cp
- (char *)&m_rtmsg
;
859 rtm
->rtm_seq
= ++seq
;
861 if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
862 if (errno
!= ESRCH
|| cmd
!= RTM_DELETE
) {
863 warn("writing to routing socket");
868 l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
869 } while (l
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= pid
));
871 warn("read from routing socket");
876 * get_ether_addr - get the hardware address of an interface on the
877 * the same subnet as ipaddr.
882 get_ether_addr(in_addr_t ipaddr
, struct ether_addr
*hwaddr
)
884 struct ifreq
*ifr
, *ifend
, *ifp
;
886 struct sockaddr_dl
*dla
;
889 struct ifreq ifs
[MAX_IFS
];
893 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
897 ifc
.ifc_len
= sizeof(ifs
);
899 if (ioctl(sock
, SIOCGIFCONF
, &ifc
) < 0) {
900 warnx("ioctl(SIOCGIFCONF)");
905 ((struct ifreq *)((char *)&(i)->ifr_addr \
906 + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) )
909 * Scan through looking for an interface with an Internet
910 * address on the same subnet as `ipaddr'.
912 ifend
= (struct ifreq
*)(ifc
.ifc_buf
+ ifc
.ifc_len
);
913 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= NEXTIFR(ifr
) ) {
914 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
916 strncpy(ifreq
.ifr_name
, ifr
->ifr_name
,
917 sizeof(ifreq
.ifr_name
));
918 ifreq
.ifr_addr
= ifr
->ifr_addr
;
920 * Check that the interface is up,
921 * and not point-to-point or loopback.
923 if (ioctl(sock
, SIOCGIFFLAGS
, &ifreq
) < 0)
925 if ((ifreq
.ifr_flags
&
926 (IFF_UP
|IFF_BROADCAST
|IFF_POINTOPOINT
|
927 IFF_LOOPBACK
|IFF_NOARP
))
928 != (IFF_UP
|IFF_BROADCAST
))
931 * Get its netmask and check that it's on
934 if (ioctl(sock
, SIOCGIFNETMASK
, &ifreq
) < 0)
936 mask
= ((struct sockaddr_in
*)
937 &ifreq
.ifr_addr
)->sin_addr
.s_addr
;
938 ina
= ((struct sockaddr_in
*)
939 &ifr
->ifr_addr
)->sin_addr
.s_addr
;
940 if ((ipaddr
& mask
) == (ina
& mask
))
941 break; /* ok, we got it! */
948 * Now scan through again looking for a link-level address
949 * for this interface.
952 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= NEXTIFR(ifr
))
953 if (strcmp(ifp
->ifr_name
, ifr
->ifr_name
) == 0 &&
954 ifr
->ifr_addr
.sa_family
== AF_LINK
)
959 * Found the link-level address - copy it out
961 dla
= (struct sockaddr_dl
*) &ifr
->ifr_addr
;
962 memcpy(hwaddr
, LLADDR(dla
), dla
->sdl_alen
);
963 printf("using interface %s for proxy with address ",
965 printf("%s\n", ether_ntoa(hwaddr
));
966 retval
= dla
->sdl_alen
;
976 static char result
[256];
977 int days
, hours
, mins
, secs
;
981 days
= total
/ 3600 / 24;
982 hours
= (total
/ 3600) % 24;
983 mins
= (total
/ 60) % 60;
988 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dd", days
);
990 if (!first
|| hours
) {
992 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dh", hours
);
994 if (!first
|| mins
) {
996 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dm", mins
);
998 snprintf(p
, sizeof(result
) - (p
- result
), "%ds", secs
);
1004 search_ext(in_addr_t addr
, action_ext_fn
*action
)
1008 char *lim
, *buf
, *newbuf
, *next
;
1009 struct rt_msghdr_ext
*ertm
;
1010 struct sockaddr_inarp
*sin2
;
1011 struct sockaddr_dl
*sdl
;
1012 char ifname
[IF_NAMESIZE
];
1013 int st
, found_entry
= 0;
1019 mib
[4] = NET_RT_DUMPX_FLAGS
;
1020 mib
[5] = RTF_LLINFO
;
1021 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1022 err(1, "route-sysctl-estimate");
1023 if (needed
== 0) /* empty table */
1027 newbuf
= realloc(buf
, needed
);
1028 if (newbuf
== NULL
) {
1031 errx(1, "could not reallocate memory");
1034 st
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
1035 if (st
== 0 || errno
!= ENOMEM
)
1037 needed
+= needed
/ 8;
1040 err(1, "actual retrieval of routing table");
1042 for (next
= buf
; next
< lim
; next
+= ertm
->rtm_msglen
) {
1043 ertm
= (struct rt_msghdr_ext
*)next
;
1044 sin2
= (struct sockaddr_inarp
*)(ertm
+ 1);
1045 sdl
= (struct sockaddr_dl
*)((char *)sin2
+ SA_SIZE(sin2
));
1046 if (rifname
&& if_indextoname(sdl
->sdl_index
, ifname
) &&
1047 strcmp(ifname
, rifname
))
1050 if (addr
!= sin2
->sin_addr
.s_addr
)
1054 (*action
)(sdl
, sin2
, ertm
);
1057 return (found_entry
);
1061 print_entry_ext(struct sockaddr_dl
*sdl
, struct sockaddr_inarp
*addr
,
1062 struct rt_msghdr_ext
*ertm
)
1066 char ifname
[IF_NAMESIZE
];
1067 struct timeval time
;
1070 hp
= gethostbyaddr((caddr_t
)&(addr
->sin_addr
),
1071 sizeof (addr
->sin_addr
), AF_INET
);
1078 host
= inet_ntoa(addr
->sin_addr
);
1080 printf("%-23s ", host
);
1083 printf("%-17s ", print_lladdr(sdl
));
1085 printf("%-17s ", "(incomplete)");
1087 gettimeofday(&time
, 0);
1089 if (ertm
->rtm_ri
.ri_refcnt
== 0 || ertm
->rtm_ri
.ri_snd_expire
== 0)
1090 printf("%-9.9s ", "(none)");
1091 else if (ertm
->rtm_ri
.ri_snd_expire
> time
.tv_sec
)
1093 sec2str(ertm
->rtm_ri
.ri_snd_expire
- time
.tv_sec
));
1095 printf("%-9.9s ", "expired");
1097 if (ertm
->rtm_ri
.ri_refcnt
== 0 || ertm
->rtm_ri
.ri_rcv_expire
== 0)
1098 printf("%-9.9s", "(none)");
1099 else if (ertm
->rtm_ri
.ri_rcv_expire
> time
.tv_sec
)
1101 sec2str(ertm
->rtm_ri
.ri_rcv_expire
- time
.tv_sec
));
1103 printf("%-9.9s", "expired");
1105 if (if_indextoname(sdl
->sdl_index
, ifname
) == NULL
)
1106 snprintf(ifname
, sizeof (ifname
), "%s", "?");
1107 printf(" %8.8s", ifname
);
1109 if (ertm
->rtm_ri
.ri_refcnt
) {
1110 printf(" %4d", ertm
->rtm_ri
.ri_refcnt
);
1111 if (ertm
->rtm_ri
.ri_probes
)
1112 printf(" %4d", ertm
->rtm_ri
.ri_probes
);
1115 if (!ertm
->rtm_ri
.ri_probes
)
1116 printf(" %-4.4s", "none");
1118 if (ertm
->rtm_ri
.ri_rssi
!= IFNET_RSSI_UNKNOWN
)
1119 printf(" %7d", ertm
->rtm_ri
.ri_rssi
);
1121 printf(" %-7.7s", "unknown");
1123 switch (ertm
->rtm_ri
.ri_lqm
)
1125 case IFNET_LQM_THRESH_OFF
:
1126 printf(" %-7.7s", "off");
1128 case IFNET_LQM_THRESH_UNKNOWN
:
1129 printf(" %-7.7s", "unknown");
1131 case IFNET_LQM_THRESH_POOR
:
1132 printf(" %-7.7s", "poor");
1134 case IFNET_LQM_THRESH_GOOD
:
1135 printf(" %-7.7s", "good");
1138 printf(" %7d", ertm
->rtm_ri
.ri_lqm
);
1142 switch (ertm
->rtm_ri
.ri_npm
)
1144 case IFNET_NPM_THRESH_UNKNOWN
:
1145 printf(" %-7.7s", "unknown");
1147 case IFNET_NPM_THRESH_NEAR
:
1148 printf(" %-7.7s", "near");
1150 case IFNET_NPM_THRESH_GENERAL
:
1151 printf(" %-7.7s", "general");
1153 case IFNET_NPM_THRESH_FAR
:
1154 printf(" %-7.7s", "far");
1157 printf(" %7d", ertm
->rtm_ri
.ri_npm
);