2 * Copyright (c) 2003-2011 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 char *rifname
;
140 static int expire_time
, flags
, doing_proxy
, proxy_only
;
142 static char *boundif
= NULL
;
143 static unsigned int ifscope
= 0;
145 /* which function we're supposed to do */
153 #define SA_SIZE(sa) \
154 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
156 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
159 #define SETFUNC(f) { if (func) usage(); func = (f); }
163 main(int argc
, char *argv
[])
167 int aflag
= 0; /* do it for all entries */
169 uint32_t ifindex
= 0;
171 while ((ch
= getopt(argc
, argv
, "andflsSi:")) != -1)
207 if (func
!= F_GET
&& !(func
== F_DELETE
&& aflag
))
208 errx(1, "-i not applicable to this operation");
209 if ((ifindex
= if_nametoindex(rifname
)) == 0) {
211 errx(1, "interface %s does not exist", rifname
);
213 err(1, "if_nametoindex(%s)", rifname
);
222 printf("%-23s %-17s %-9.9s %-9.9s %8.8s %4s "
223 "%4s\n", "Neighbor", "Linklayer Address",
224 "Expire(O)", "Expire(I)", "Netif", "Refs",
226 search_ext(0, print_entry_ext
);
228 search(0, print_entry
);
238 if (argc
< 2 || argc
> 6)
240 if (func
== F_REPLACE
)
241 (void)delete(argv
[0], 0);
242 rtn
= set(argc
, argv
) ? 1 : 0;
248 search(0, nuke_entry
);
253 for (i
= 1; i
< argc
; i
++) {
254 if (strncmp(argv
[i
], "pub", sizeof("pub")) == 0) {
255 do_proxy
= SIN_PROXY
;
256 } else if (strncmp(argv
[i
], "ifscope", sizeof("ifscope")) == 0) {
258 printf("ifscope needs an interface parameter\n");
262 if ((ifscope
= if_nametoindex(boundif
)) == 0)
263 errx(1, "ifscope has bad interface name: %s", boundif
);
270 rtn
= delete(argv
[0], do_proxy
);
284 * Process a file to set standard arp entries
291 char line
[128], arg
[7][50], *args
[7], *p
;
293 if ((fp
= fopen(name
, "r")) == NULL
)
294 err(1, "cannot open %s", name
);
295 args
[0] = &arg
[0][0];
296 args
[1] = &arg
[1][0];
297 args
[2] = &arg
[2][0];
298 args
[3] = &arg
[3][0];
299 args
[4] = &arg
[4][0];
300 args
[5] = &arg
[5][0];
301 args
[6] = &arg
[6][0];
303 while(fgets(line
, sizeof(line
), fp
) != NULL
) {
304 if ((p
= strchr(line
, '#')) != NULL
)
306 for (p
= line
; isblank(*p
); p
++);
307 if (*p
== '\n' || *p
== '\0')
309 i
= sscanf(p
, "%49s %49s %49s %49s %49s %49s %49s", arg
[0], arg
[1],
310 arg
[2], arg
[3], arg
[4], arg
[5], arg
[6]);
312 warnx("bad line: %s", line
);
324 * Given a hostname, fills up a (static) struct sockaddr_inarp with
325 * the address of the host and returns a pointer to the
328 static struct sockaddr_inarp
*
332 static struct sockaddr_inarp reply
;
334 bzero(&reply
, sizeof(reply
));
335 reply
.sin_len
= sizeof(reply
);
336 reply
.sin_family
= AF_INET
;
337 reply
.sin_addr
.s_addr
= inet_addr(host
);
338 if (reply
.sin_addr
.s_addr
== INADDR_NONE
) {
339 if (!(hp
= gethostbyname(host
))) {
340 warnx("%s: %s", host
, hstrerror(h_errno
));
343 bcopy((char *)hp
->h_addr
, (char *)&reply
.sin_addr
,
344 sizeof reply
.sin_addr
);
350 * Returns true if the type is a valid one for ARP.
375 * Set an individual arp entry
378 set(int argc
, char **argv
)
380 struct sockaddr_inarp
*addr
;
381 struct sockaddr_inarp
*dst
; /* what are we looking for */
382 struct sockaddr_dl
*sdl
;
383 struct rt_msghdr
*rtm
;
384 struct ether_addr
*ea
;
385 char *host
= argv
[0], *eaddr
= argv
[1];
386 struct sockaddr_dl sdl_m
;
391 bzero(&sdl_m
, sizeof(sdl_m
));
392 sdl_m
.sdl_len
= sizeof(sdl_m
);
393 sdl_m
.sdl_family
= AF_LINK
;
398 doing_proxy
= flags
= proxy_only
= expire_time
= 0;
402 if (strncmp(argv
[0], "temp", sizeof("temp")) == 0) {
404 gettimeofday(&tv
, 0);
405 expire_time
= tv
.tv_sec
+ 20 * 60;
406 } else if (strncmp(argv
[0], "pub", sizeof("pub")) == 0) {
407 flags
|= RTF_ANNOUNCE
;
409 if (argc
&& strncmp(argv
[1], "only", sizeof("only")) == 0) {
411 dst
->sin_other
= SIN_PROXY
;
414 } else if (strncmp(argv
[0], "blackhole", sizeof("blackhole")) == 0) {
415 flags
|= RTF_BLACKHOLE
;
416 } else if (strncmp(argv
[0], "reject", sizeof("reject")) == 0) {
418 } else if (strncmp(argv
[0], "trail", sizeof("trail")) == 0) {
419 /* XXX deprecated and undocumented feature */
420 printf("%s: Sending trailers is no longer supported\n",
422 } else if (strncmp(argv
[0], "ifscope", sizeof("ifscope")) == 0) {
424 printf("ifscope needs an interface parameter\n");
428 if ((ifscope
= if_nametoindex(boundif
)) == 0)
429 errx(1, "ifscope has bad interface name: %s", boundif
);
434 ea
= (struct ether_addr
*)LLADDR(&sdl_m
);
435 if (doing_proxy
&& !strcmp(eaddr
, "auto")) {
436 if (!get_ether_addr(dst
->sin_addr
.s_addr
, ea
)) {
437 printf("no interface found for %s\n",
438 inet_ntoa(dst
->sin_addr
));
441 sdl_m
.sdl_alen
= ETHER_ADDR_LEN
;
443 struct ether_addr
*ea1
= ether_aton(eaddr
);
446 warnx("invalid Ethernet address '%s'", eaddr
);
450 sdl_m
.sdl_alen
= ETHER_ADDR_LEN
;
453 for (;;) { /* try at most twice */
454 rtm
= rtmsg(RTM_GET
, dst
, &sdl_m
);
459 addr
= (struct sockaddr_inarp
*)(rtm
+ 1);
460 sdl
= (struct sockaddr_dl
*)(SA_SIZE(addr
) + (char *)addr
);
461 if (addr
->sin_addr
.s_addr
!= dst
->sin_addr
.s_addr
)
463 if (sdl
->sdl_family
== AF_LINK
&&
464 (rtm
->rtm_flags
& RTF_LLINFO
) &&
465 !(rtm
->rtm_flags
& RTF_GATEWAY
) &&
466 valid_type(sdl
->sdl_type
) )
469 * If we asked for a scope entry and did not get one or
470 * did not asked for a scope entry and got one, we can
473 if ((ifscope
!= 0) != (rtm
->rtm_flags
& RTF_IFSCOPE
))
475 if (doing_proxy
== 0) {
476 printf("set: can only proxy for %s\n", host
);
479 if (dst
->sin_other
& SIN_PROXY
) {
480 printf("set: proxy entry exists for non 802 device\n");
483 dst
->sin_other
= SIN_PROXY
;
487 if (sdl
->sdl_family
!= AF_LINK
) {
488 printf("cannot intuit interface index and type for %s\n", host
);
491 sdl_m
.sdl_type
= sdl
->sdl_type
;
492 sdl_m
.sdl_index
= sdl
->sdl_index
;
493 return (rtmsg(RTM_ADD
, dst
, &sdl_m
) == NULL
);
497 * Display an individual arp entry
502 struct sockaddr_inarp
*addr
;
504 addr
= getaddr(host
);
507 if (0 == search(addr
->sin_addr
.s_addr
, print_entry
)) {
508 printf("%s (%s) -- no entry",
509 host
, inet_ntoa(addr
->sin_addr
));
511 printf(" on %s", rifname
);
519 * Delete an arp entry
522 delete(char *host
, int do_proxy
)
524 struct sockaddr_inarp
*addr
, *dst
;
525 struct rt_msghdr
*rtm
;
526 struct sockaddr_dl
*sdl
;
531 dst
->sin_other
= do_proxy
;
532 for (;;) { /* try twice */
533 rtm
= rtmsg(RTM_GET
, dst
, NULL
);
538 addr
= (struct sockaddr_inarp
*)(rtm
+ 1);
539 sdl
= (struct sockaddr_dl
*)(SA_SIZE(addr
) + (char *)addr
);
540 if (addr
->sin_addr
.s_addr
== dst
->sin_addr
.s_addr
&&
541 sdl
->sdl_family
== AF_LINK
&&
542 (rtm
->rtm_flags
& RTF_LLINFO
) &&
543 !(rtm
->rtm_flags
& RTF_GATEWAY
) &&
544 valid_type(sdl
->sdl_type
) )
545 break; /* found it */
546 if (dst
->sin_other
& SIN_PROXY
) {
547 fprintf(stderr
, "delete: cannot locate %s\n",host
);
550 dst
->sin_other
= SIN_PROXY
;
552 if (rtmsg(RTM_DELETE
, dst
, NULL
) != NULL
) {
553 printf("%s (%s) deleted\n", host
, inet_ntoa(addr
->sin_addr
));
560 * Search the arp table and do some action on matching entries
563 search(in_addr_t addr
, action_fn
*action
)
567 char *lim
, *buf
, *newbuf
, *next
;
568 struct rt_msghdr
*rtm
;
569 struct sockaddr_inarp
*sin2
;
570 struct sockaddr_dl
*sdl
;
571 char ifname
[IF_NAMESIZE
];
572 int st
, found_entry
= 0;
578 mib
[4] = NET_RT_FLAGS
;
580 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
581 err(1, "route-sysctl-estimate");
582 if (needed
== 0) /* empty table */
586 newbuf
= realloc(buf
, needed
);
587 if (newbuf
== NULL
) {
590 errx(1, "could not reallocate memory");
593 st
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
594 if (st
== 0 || errno
!= ENOMEM
)
596 needed
+= needed
/ 8;
599 err(1, "actual retrieval of routing table");
601 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
602 rtm
= (struct rt_msghdr
*)next
;
603 sin2
= (struct sockaddr_inarp
*)(rtm
+ 1);
604 sdl
= (struct sockaddr_dl
*)((char *)sin2
+ SA_SIZE(sin2
));
605 if (rifname
&& if_indextoname(sdl
->sdl_index
, ifname
) &&
606 strcmp(ifname
, rifname
))
609 if (addr
!= sin2
->sin_addr
.s_addr
)
613 (*action
)(sdl
, sin2
, rtm
);
616 return (found_entry
);
620 * Stolen and adapted from ifconfig
623 print_lladdr(struct sockaddr_dl
*sdl
)
625 static char buf
[256];
627 int n
, bufsize
= sizeof (buf
), p
= 0;
629 bzero(buf
, sizeof (buf
));
630 cp
= (char *)LLADDR(sdl
);
631 if ((n
= sdl
->sdl_alen
) > 0) {
633 p
+= snprintf(buf
+ p
, bufsize
- p
, "%x%s",
634 *cp
++ & 0xff, n
> 0 ? ":" : "");
640 * Display an arp entry
643 print_entry(struct sockaddr_dl
*sdl
,
644 struct sockaddr_inarp
*addr
, struct rt_msghdr
*rtm
)
648 char ifname
[IF_NAMESIZE
];
650 struct iso88025_sockaddr_dl_data
*trld
;
655 hp
= gethostbyaddr((caddr_t
)&(addr
->sin_addr
),
656 sizeof addr
->sin_addr
, AF_INET
);
663 if (h_errno
== TRY_AGAIN
)
666 printf("%s (%s) at ", host
, inet_ntoa(addr
->sin_addr
));
669 printf("%s", print_lladdr(sdl
));
671 if ((sdl
->sdl_type
== IFT_ETHER
||
672 sdl
->sdl_type
== IFT_L2VLAN
||
673 sdl
->sdl_type
== IFT_BRIDGE
) &&
674 sdl
->sdl_alen
== ETHER_ADDR_LEN
)
675 printf("%s", ether_ntoa((struct ether_addr
*)LLADDR(sdl
)));
677 int n
= sdl
->sdl_nlen
> 0 ? sdl
->sdl_nlen
+ 1 : 0;
679 printf("%s", link_ntoa(sdl
) + n
);
683 printf("(incomplete)");
684 if (if_indextoname(sdl
->sdl_index
, ifname
) != NULL
)
685 printf(" on %s", ifname
);
686 if ((rtm
->rtm_flags
& RTF_IFSCOPE
))
688 if (rtm
->rtm_rmx
.rmx_expire
== 0)
689 printf(" permanent");
690 if (addr
->sin_other
& SIN_PROXY
)
691 printf(" published (proxy only)");
692 if (rtm
->rtm_addrs
& RTA_NETMASK
) {
693 addr
= (struct sockaddr_inarp
*)
694 (SA_SIZE(sdl
) + (char *)sdl
);
695 if (addr
->sin_addr
.s_addr
== 0xffffffff)
696 printf(" published");
697 if (addr
->sin_len
!= 8)
700 switch(sdl
->sdl_type
) {
702 printf(" [ethernet]");
706 printf(" [token-ring]");
707 trld
= SDL_ISO88025(sdl
);
708 if (trld
->trld_rcf
!= 0) {
709 printf(" rt=%x", ntohs(trld
->trld_rcf
));
711 seg
< ((TR_RCF_RIFLEN(trld
->trld_rcf
) - 2 ) / 2);
713 printf(":%x", ntohs(*(trld
->trld_route
[seg
])));
727 printf(" [firewire]");
746 nuke_entry(struct sockaddr_dl
*sdl __unused
,
747 struct sockaddr_inarp
*addr
, struct rt_msghdr
*rtm
)
751 snprintf(ip
, sizeof(ip
), "%s", inet_ntoa(addr
->sin_addr
));
753 * When deleting all entries, specify the interface scope of each entry
755 if ((rtm
->rtm_flags
& RTF_IFSCOPE
))
756 ifscope
= rtm
->rtm_index
;
764 fprintf(stderr
, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
765 "usage: arp [-n] [-i interface] hostname",
766 " arp [-n] [-i interface] [-l] -a",
767 " arp -d hostname [pub] [ifscope interface]",
768 " arp -d [-i interface] -a",
769 " arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
770 " arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
775 static struct rt_msghdr
*
776 rtmsg(int cmd
, struct sockaddr_inarp
*dst
, struct sockaddr_dl
*sdl
)
781 struct sockaddr_in so_mask
, *so_mask_ptr
= &so_mask
;
786 struct rt_msghdr m_rtm
;
790 struct rt_msghdr
*rtm
= &m_rtmsg
.m_rtm
;
791 char *cp
= m_rtmsg
.m_space
;
793 if (s
< 0) { /* first time: open socket, get pid */
794 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
799 bzero(&so_mask
, sizeof(so_mask
));
801 so_mask
.sin_addr
.s_addr
= 0xffffffff;
805 * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer
806 * appropriately (except for the mask set just above).
808 if (cmd
== RTM_DELETE
)
810 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
811 rtm
->rtm_flags
= flags
;
812 rtm
->rtm_version
= RTM_VERSION
;
815 * Note: On RTM_GET the kernel will return a scoped route when both a scoped route and
816 * a unscoped route exist. That means we cannot delete a unscoped route if there is
817 * also a matching scope route
820 rtm
->rtm_index
= ifscope
;
821 rtm
->rtm_flags
|= RTF_IFSCOPE
;
826 errx(1, "internal wrong cmd");
828 rtm
->rtm_addrs
|= RTA_GATEWAY
;
829 rtm
->rtm_rmx
.rmx_expire
= expire_time
;
830 rtm
->rtm_inits
= RTV_EXPIRE
;
831 rtm
->rtm_flags
|= (RTF_HOST
| RTF_STATIC
);
835 dst
->sin_other
= SIN_PROXY
;
837 rtm
->rtm_addrs
|= RTA_NETMASK
;
838 rtm
->rtm_flags
&= ~RTF_HOST
;
843 rtm
->rtm_addrs
|= RTA_DST
;
845 #define NEXTADDR(w, s) \
846 if ((s) != NULL && rtm->rtm_addrs & (w)) { \
847 bcopy((s), cp, sizeof(*(s))); cp += SA_SIZE(s);}
849 NEXTADDR(RTA_DST
, dst
);
850 NEXTADDR(RTA_GATEWAY
, sdl
);
851 NEXTADDR(RTA_NETMASK
, so_mask_ptr
);
853 rtm
->rtm_msglen
= cp
- (char *)&m_rtmsg
;
856 rtm
->rtm_seq
= ++seq
;
858 if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
859 if (errno
!= ESRCH
|| cmd
!= RTM_DELETE
) {
860 warn("writing to routing socket");
865 l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
866 } while (l
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= pid
));
868 warn("read from routing socket");
873 * get_ether_addr - get the hardware address of an interface on the
874 * the same subnet as ipaddr.
879 get_ether_addr(in_addr_t ipaddr
, struct ether_addr
*hwaddr
)
881 struct ifreq
*ifr
, *ifend
, *ifp
;
883 struct sockaddr_dl
*dla
;
886 struct ifreq ifs
[MAX_IFS
];
890 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
894 ifc
.ifc_len
= sizeof(ifs
);
896 if (ioctl(sock
, SIOCGIFCONF
, &ifc
) < 0) {
897 warnx("ioctl(SIOCGIFCONF)");
902 ((struct ifreq *)((char *)&(i)->ifr_addr \
903 + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) )
906 * Scan through looking for an interface with an Internet
907 * address on the same subnet as `ipaddr'.
909 ifend
= (struct ifreq
*)(ifc
.ifc_buf
+ ifc
.ifc_len
);
910 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= NEXTIFR(ifr
) ) {
911 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
913 strncpy(ifreq
.ifr_name
, ifr
->ifr_name
,
914 sizeof(ifreq
.ifr_name
));
915 ifreq
.ifr_addr
= ifr
->ifr_addr
;
917 * Check that the interface is up,
918 * and not point-to-point or loopback.
920 if (ioctl(sock
, SIOCGIFFLAGS
, &ifreq
) < 0)
922 if ((ifreq
.ifr_flags
&
923 (IFF_UP
|IFF_BROADCAST
|IFF_POINTOPOINT
|
924 IFF_LOOPBACK
|IFF_NOARP
))
925 != (IFF_UP
|IFF_BROADCAST
))
928 * Get its netmask and check that it's on
931 if (ioctl(sock
, SIOCGIFNETMASK
, &ifreq
) < 0)
933 mask
= ((struct sockaddr_in
*)
934 &ifreq
.ifr_addr
)->sin_addr
.s_addr
;
935 ina
= ((struct sockaddr_in
*)
936 &ifr
->ifr_addr
)->sin_addr
.s_addr
;
937 if ((ipaddr
& mask
) == (ina
& mask
))
938 break; /* ok, we got it! */
945 * Now scan through again looking for a link-level address
946 * for this interface.
949 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= NEXTIFR(ifr
))
950 if (strcmp(ifp
->ifr_name
, ifr
->ifr_name
) == 0 &&
951 ifr
->ifr_addr
.sa_family
== AF_LINK
)
956 * Found the link-level address - copy it out
958 dla
= (struct sockaddr_dl
*) &ifr
->ifr_addr
;
959 memcpy(hwaddr
, LLADDR(dla
), dla
->sdl_alen
);
960 printf("using interface %s for proxy with address ",
962 printf("%s\n", ether_ntoa(hwaddr
));
963 retval
= dla
->sdl_alen
;
973 static char result
[256];
974 int days
, hours
, mins
, secs
;
978 days
= total
/ 3600 / 24;
979 hours
= (total
/ 3600) % 24;
980 mins
= (total
/ 60) % 60;
985 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dd", days
);
987 if (!first
|| hours
) {
989 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dh", hours
);
991 if (!first
|| mins
) {
993 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dm", mins
);
995 snprintf(p
, sizeof(result
) - (p
- result
), "%ds", secs
);
1001 search_ext(in_addr_t addr
, action_ext_fn
*action
)
1005 char *lim
, *buf
, *newbuf
, *next
;
1006 struct rt_msghdr_ext
*ertm
;
1007 struct sockaddr_inarp
*sin2
;
1008 struct sockaddr_dl
*sdl
;
1009 char ifname
[IF_NAMESIZE
];
1010 int st
, found_entry
= 0;
1016 mib
[4] = NET_RT_DUMPX_FLAGS
;
1017 mib
[5] = RTF_LLINFO
;
1018 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1019 err(1, "route-sysctl-estimate");
1020 if (needed
== 0) /* empty table */
1024 newbuf
= realloc(buf
, needed
);
1025 if (newbuf
== NULL
) {
1028 errx(1, "could not reallocate memory");
1031 st
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
1032 if (st
== 0 || errno
!= ENOMEM
)
1034 needed
+= needed
/ 8;
1037 err(1, "actual retrieval of routing table");
1039 for (next
= buf
; next
< lim
; next
+= ertm
->rtm_msglen
) {
1040 ertm
= (struct rt_msghdr_ext
*)next
;
1041 sin2
= (struct sockaddr_inarp
*)(ertm
+ 1);
1042 sdl
= (struct sockaddr_dl
*)((char *)sin2
+ SA_SIZE(sin2
));
1043 if (rifname
&& if_indextoname(sdl
->sdl_index
, ifname
) &&
1044 strcmp(ifname
, rifname
))
1047 if (addr
!= sin2
->sin_addr
.s_addr
)
1051 (*action
)(sdl
, sin2
, ertm
);
1054 return (found_entry
);
1058 print_entry_ext(struct sockaddr_dl
*sdl
, struct sockaddr_inarp
*addr
,
1059 struct rt_msghdr_ext
*ertm
)
1063 char ifname
[IF_NAMESIZE
];
1064 struct timeval time
;
1067 hp
= gethostbyaddr((caddr_t
)&(addr
->sin_addr
),
1068 sizeof (addr
->sin_addr
), AF_INET
);
1075 host
= inet_ntoa(addr
->sin_addr
);
1077 printf("%-23s ", host
);
1080 printf("%-17s ", print_lladdr(sdl
));
1082 printf("%-17s ", "(incomplete)");
1084 gettimeofday(&time
, 0);
1086 if (ertm
->rtm_ri
.ri_refcnt
== 0 || ertm
->rtm_ri
.ri_snd_expire
== 0)
1087 printf("%-9.9s ", "(none)");
1088 else if (ertm
->rtm_ri
.ri_snd_expire
> time
.tv_sec
)
1090 sec2str(ertm
->rtm_ri
.ri_snd_expire
- time
.tv_sec
));
1092 printf("%-9.9s ", "expired");
1094 if (ertm
->rtm_ri
.ri_refcnt
== 0 || ertm
->rtm_ri
.ri_rcv_expire
== 0)
1095 printf("%-9.9s", "(none)");
1096 else if (ertm
->rtm_ri
.ri_rcv_expire
> time
.tv_sec
)
1098 sec2str(ertm
->rtm_ri
.ri_rcv_expire
- time
.tv_sec
));
1100 printf("%-9.9s", "expired");
1102 if (if_indextoname(sdl
->sdl_index
, ifname
) == NULL
)
1103 snprintf(ifname
, sizeof (ifname
), "%s", "?");
1104 printf(" %8.8s", ifname
);
1106 if (ertm
->rtm_ri
.ri_refcnt
) {
1107 printf(" %4d", ertm
->rtm_ri
.ri_refcnt
);
1108 if (ertm
->rtm_ri
.ri_probes
)
1109 printf(" %4d", ertm
->rtm_ri
.ri_probes
);