2 * Copyright (c) 1984, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Sun Microsystems, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 static char const copyright
[] =
36 "@(#) Copyright (c) 1984, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
41 static char const sccsid
[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94";
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD: src/usr.sbin/arp/arp.c,v 1.65.2.1 2008/04/25 16:38:14 sam Exp $");
48 * arp - display, set, and delete arp table entries
52 #include <sys/param.h>
54 #include <sys/socket.h>
55 #include <sys/sockio.h>
56 #include <sys/sysctl.h>
57 #include <sys/ioctl.h>
61 #include <net/if_dl.h>
62 #include <net/if_types.h>
63 #include <net/route.h>
65 #include <net/iso88025.h>
68 #include <netinet/in.h>
69 #include <netinet/if_ether.h>
71 #include <arpa/inet.h>
85 typedef void (action_fn
)(struct sockaddr_dl
*sdl
,
86 struct sockaddr_inarp
*s_in
, struct rt_msghdr
*rtm
);
88 static int search(in_addr_t addr
, action_fn
*action
);
89 static action_fn print_entry
;
90 static action_fn nuke_entry
;
92 static int delete(char *host
, int do_proxy
);
93 static void usage(void);
94 static int set(int argc
, char **argv
);
95 static int get(char *host
);
96 static int file(char *name
);
97 static struct rt_msghdr
*rtmsg(int cmd
,
98 struct sockaddr_inarp
*dst
, struct sockaddr_dl
*sdl
);
99 static int get_ether_addr(in_addr_t ipaddr
, struct ether_addr
*hwaddr
);
100 static struct sockaddr_inarp
*getaddr(char *host
);
101 static int valid_type(int type
);
103 static int nflag
; /* no reverse dns lookups */
104 static char *rifname
;
106 static int expire_time
, flags
, doing_proxy
, proxy_only
;
108 static char *boundif
= NULL
;
109 static unsigned int ifscope
= 0;
111 /* which function we're supposed to do */
119 #define SA_SIZE(sa) \
120 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
122 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
125 #define SETFUNC(f) { if (func) usage(); func = (f); }
129 main(int argc
, char *argv
[])
133 int aflag
= 0; /* do it for all entries */
135 while ((ch
= getopt(argc
, argv
, "andfsSi:")) != -1)
168 if (func
!= F_GET
&& !(func
== F_DELETE
&& aflag
))
169 errx(1, "-i not applicable to this operation");
170 if (if_nametoindex(rifname
) == 0) {
172 errx(1, "interface %s does not exist", rifname
);
174 err(1, "if_nametoindex(%s)", rifname
);
182 search(0, print_entry
);
191 if (argc
< 2 || argc
> 6)
193 if (func
== F_REPLACE
)
194 (void)delete(argv
[0], 0);
195 rtn
= set(argc
, argv
) ? 1 : 0;
201 search(0, nuke_entry
);
206 for (i
= 1; i
< argc
; i
++) {
207 if (strncmp(argv
[i
], "pub", sizeof("pub")) == 0) {
208 do_proxy
= SIN_PROXY
;
209 } else if (strncmp(argv
[i
], "ifscope", sizeof("ifscope")) == 0) {
211 printf("ifscope needs an interface parameter\n");
215 if ((ifscope
= if_nametoindex(boundif
)) == 0)
216 errx(1, "ifscope has bad interface name: %s", boundif
);
221 rtn
= delete(argv
[0], do_proxy
);
235 * Process a file to set standard arp entries
242 char line
[128], arg
[7][50], *args
[7], *p
;
244 if ((fp
= fopen(name
, "r")) == NULL
)
245 err(1, "cannot open %s", name
);
246 args
[0] = &arg
[0][0];
247 args
[1] = &arg
[1][0];
248 args
[2] = &arg
[2][0];
249 args
[3] = &arg
[3][0];
250 args
[4] = &arg
[4][0];
251 args
[5] = &arg
[5][0];
252 args
[6] = &arg
[6][0];
254 while(fgets(line
, sizeof(line
), fp
) != NULL
) {
255 if ((p
= strchr(line
, '#')) != NULL
)
257 for (p
= line
; isblank(*p
); p
++);
258 if (*p
== '\n' || *p
== '\0')
260 i
= sscanf(p
, "%49s %49s %49s %49s %49s %49s %49s", arg
[0], arg
[1],
261 arg
[2], arg
[3], arg
[4], arg
[5], arg
[6]);
263 warnx("bad line: %s", line
);
275 * Given a hostname, fills up a (static) struct sockaddr_inarp with
276 * the address of the host and returns a pointer to the
279 static struct sockaddr_inarp
*
283 static struct sockaddr_inarp reply
;
285 bzero(&reply
, sizeof(reply
));
286 reply
.sin_len
= sizeof(reply
);
287 reply
.sin_family
= AF_INET
;
288 reply
.sin_addr
.s_addr
= inet_addr(host
);
289 if (reply
.sin_addr
.s_addr
== INADDR_NONE
) {
290 if (!(hp
= gethostbyname(host
))) {
291 warnx("%s: %s", host
, hstrerror(h_errno
));
294 bcopy((char *)hp
->h_addr
, (char *)&reply
.sin_addr
,
295 sizeof reply
.sin_addr
);
301 * Returns true if the type is a valid one for ARP.
326 * Set an individual arp entry
329 set(int argc
, char **argv
)
331 struct sockaddr_inarp
*addr
;
332 struct sockaddr_inarp
*dst
; /* what are we looking for */
333 struct sockaddr_dl
*sdl
;
334 struct rt_msghdr
*rtm
;
335 struct ether_addr
*ea
;
336 char *host
= argv
[0], *eaddr
= argv
[1];
337 struct sockaddr_dl sdl_m
;
342 bzero(&sdl_m
, sizeof(sdl_m
));
343 sdl_m
.sdl_len
= sizeof(sdl_m
);
344 sdl_m
.sdl_family
= AF_LINK
;
349 doing_proxy
= flags
= proxy_only
= expire_time
= 0;
353 if (strncmp(argv
[0], "temp", sizeof("temp")) == 0) {
355 gettimeofday(&tv
, 0);
356 expire_time
= tv
.tv_sec
+ 20 * 60;
357 } else if (strncmp(argv
[0], "pub", sizeof("pub")) == 0) {
358 flags
|= RTF_ANNOUNCE
;
360 if (argc
&& strncmp(argv
[1], "only", sizeof("only")) == 0) {
362 dst
->sin_other
= SIN_PROXY
;
365 } else if (strncmp(argv
[0], "blackhole", sizeof("blackhole")) == 0) {
366 flags
|= RTF_BLACKHOLE
;
367 } else if (strncmp(argv
[0], "reject", sizeof("reject")) == 0) {
369 } else if (strncmp(argv
[0], "trail", sizeof("trail")) == 0) {
370 /* XXX deprecated and undocumented feature */
371 printf("%s: Sending trailers is no longer supported\n",
373 } else if (strncmp(argv
[0], "ifscope", sizeof("ifscope")) == 0) {
375 printf("ifscope needs an interface parameter\n");
379 if ((ifscope
= if_nametoindex(boundif
)) == 0)
380 errx(1, "ifscope has bad interface name: %s", boundif
);
385 ea
= (struct ether_addr
*)LLADDR(&sdl_m
);
386 if (doing_proxy
&& !strcmp(eaddr
, "auto")) {
387 if (!get_ether_addr(dst
->sin_addr
.s_addr
, ea
)) {
388 printf("no interface found for %s\n",
389 inet_ntoa(dst
->sin_addr
));
392 sdl_m
.sdl_alen
= ETHER_ADDR_LEN
;
394 struct ether_addr
*ea1
= ether_aton(eaddr
);
397 warnx("invalid Ethernet address '%s'", eaddr
);
401 sdl_m
.sdl_alen
= ETHER_ADDR_LEN
;
404 for (;;) { /* try at most twice */
405 rtm
= rtmsg(RTM_GET
, dst
, &sdl_m
);
410 addr
= (struct sockaddr_inarp
*)(rtm
+ 1);
411 sdl
= (struct sockaddr_dl
*)(SA_SIZE(addr
) + (char *)addr
);
412 if (addr
->sin_addr
.s_addr
!= dst
->sin_addr
.s_addr
)
414 if (sdl
->sdl_family
== AF_LINK
&&
415 (rtm
->rtm_flags
& RTF_LLINFO
) &&
416 !(rtm
->rtm_flags
& RTF_GATEWAY
) &&
417 valid_type(sdl
->sdl_type
) )
420 * If we asked for a scope entry and did not get one or
421 * did not asked for a scope entry and got one, we can
424 if ((ifscope
!= 0) != (rtm
->rtm_flags
& RTF_IFSCOPE
))
426 if (doing_proxy
== 0) {
427 printf("set: can only proxy for %s\n", host
);
430 if (dst
->sin_other
& SIN_PROXY
) {
431 printf("set: proxy entry exists for non 802 device\n");
434 dst
->sin_other
= SIN_PROXY
;
438 if (sdl
->sdl_family
!= AF_LINK
) {
439 printf("cannot intuit interface index and type for %s\n", host
);
442 sdl_m
.sdl_type
= sdl
->sdl_type
;
443 sdl_m
.sdl_index
= sdl
->sdl_index
;
444 return (rtmsg(RTM_ADD
, dst
, &sdl_m
) == NULL
);
448 * Display an individual arp entry
453 struct sockaddr_inarp
*addr
;
455 addr
= getaddr(host
);
458 if (0 == search(addr
->sin_addr
.s_addr
, print_entry
)) {
459 printf("%s (%s) -- no entry",
460 host
, inet_ntoa(addr
->sin_addr
));
462 printf(" on %s", rifname
);
470 * Delete an arp entry
473 delete(char *host
, int do_proxy
)
475 struct sockaddr_inarp
*addr
, *dst
;
476 struct rt_msghdr
*rtm
;
477 struct sockaddr_dl
*sdl
;
482 dst
->sin_other
= do_proxy
;
483 for (;;) { /* try twice */
484 rtm
= rtmsg(RTM_GET
, dst
, NULL
);
489 addr
= (struct sockaddr_inarp
*)(rtm
+ 1);
490 sdl
= (struct sockaddr_dl
*)(SA_SIZE(addr
) + (char *)addr
);
491 if (addr
->sin_addr
.s_addr
== dst
->sin_addr
.s_addr
&&
492 sdl
->sdl_family
== AF_LINK
&&
493 (rtm
->rtm_flags
& RTF_LLINFO
) &&
494 !(rtm
->rtm_flags
& RTF_GATEWAY
) &&
495 valid_type(sdl
->sdl_type
) )
496 break; /* found it */
497 if (dst
->sin_other
& SIN_PROXY
) {
498 fprintf(stderr
, "delete: cannot locate %s\n",host
);
501 dst
->sin_other
= SIN_PROXY
;
503 if (rtmsg(RTM_DELETE
, dst
, NULL
) != NULL
) {
504 printf("%s (%s) deleted\n", host
, inet_ntoa(addr
->sin_addr
));
511 * Search the arp table and do some action on matching entries
514 search(in_addr_t addr
, action_fn
*action
)
518 char *lim
, *buf
, *newbuf
, *next
;
519 struct rt_msghdr
*rtm
;
520 struct sockaddr_inarp
*sin2
;
521 struct sockaddr_dl
*sdl
;
522 char ifname
[IF_NAMESIZE
];
523 int st
, found_entry
= 0;
529 mib
[4] = NET_RT_FLAGS
;
531 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
532 err(1, "route-sysctl-estimate");
533 if (needed
== 0) /* empty table */
537 newbuf
= realloc(buf
, needed
);
538 if (newbuf
== NULL
) {
541 errx(1, "could not reallocate memory");
544 st
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
545 if (st
== 0 || errno
!= ENOMEM
)
547 needed
+= needed
/ 8;
550 err(1, "actual retrieval of routing table");
552 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
553 rtm
= (struct rt_msghdr
*)next
;
554 sin2
= (struct sockaddr_inarp
*)(rtm
+ 1);
555 sdl
= (struct sockaddr_dl
*)((char *)sin2
+ SA_SIZE(sin2
));
556 if (rifname
&& if_indextoname(sdl
->sdl_index
, ifname
) &&
557 strcmp(ifname
, rifname
))
560 if (addr
!= sin2
->sin_addr
.s_addr
)
564 (*action
)(sdl
, sin2
, rtm
);
567 return (found_entry
);
571 * Stolen and adapted from ifconfig
574 print_lladdr(struct sockaddr_dl
*sdl
)
579 cp
= (char *)LLADDR(sdl
);
580 if ((n
= sdl
->sdl_alen
) > 0) {
582 printf("%x%s",*cp
++ & 0xff, n
>0? ":" : "");
588 * Display an arp entry
591 print_entry(struct sockaddr_dl
*sdl
,
592 struct sockaddr_inarp
*addr
, struct rt_msghdr
*rtm
)
596 char ifname
[IF_NAMESIZE
];
598 struct iso88025_sockaddr_dl_data
*trld
;
603 hp
= gethostbyaddr((caddr_t
)&(addr
->sin_addr
),
604 sizeof addr
->sin_addr
, AF_INET
);
611 if (h_errno
== TRY_AGAIN
)
614 printf("%s (%s) at ", host
, inet_ntoa(addr
->sin_addr
));
619 if ((sdl
->sdl_type
== IFT_ETHER
||
620 sdl
->sdl_type
== IFT_L2VLAN
||
621 sdl
->sdl_type
== IFT_BRIDGE
) &&
622 sdl
->sdl_alen
== ETHER_ADDR_LEN
)
623 printf("%s", ether_ntoa((struct ether_addr
*)LLADDR(sdl
)));
625 int n
= sdl
->sdl_nlen
> 0 ? sdl
->sdl_nlen
+ 1 : 0;
627 printf("%s", link_ntoa(sdl
) + n
);
631 printf("(incomplete)");
632 if (if_indextoname(sdl
->sdl_index
, ifname
) != NULL
)
633 printf(" on %s", ifname
);
634 if ((rtm
->rtm_flags
& RTF_IFSCOPE
))
636 if (rtm
->rtm_rmx
.rmx_expire
== 0)
637 printf(" permanent");
638 if (addr
->sin_other
& SIN_PROXY
)
639 printf(" published (proxy only)");
640 if (rtm
->rtm_addrs
& RTA_NETMASK
) {
641 addr
= (struct sockaddr_inarp
*)
642 (SA_SIZE(sdl
) + (char *)sdl
);
643 if (addr
->sin_addr
.s_addr
== 0xffffffff)
644 printf(" published");
645 if (addr
->sin_len
!= 8)
648 switch(sdl
->sdl_type
) {
650 printf(" [ethernet]");
654 printf(" [token-ring]");
655 trld
= SDL_ISO88025(sdl
);
656 if (trld
->trld_rcf
!= 0) {
657 printf(" rt=%x", ntohs(trld
->trld_rcf
));
659 seg
< ((TR_RCF_RIFLEN(trld
->trld_rcf
) - 2 ) / 2);
661 printf(":%x", ntohs(*(trld
->trld_route
[seg
])));
675 printf(" [firewire]");
694 nuke_entry(struct sockaddr_dl
*sdl __unused
,
695 struct sockaddr_inarp
*addr
, struct rt_msghdr
*rtm __unused
)
699 snprintf(ip
, sizeof(ip
), "%s", inet_ntoa(addr
->sin_addr
));
706 fprintf(stderr
, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
707 "usage: arp [-n] [-i interface] hostname",
708 " arp [-n] [-i interface] -a",
709 " arp -d hostname [pub] [ifscope interface]",
710 " arp -d [-i interface] -a",
711 " arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
712 " arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
717 static struct rt_msghdr
*
718 rtmsg(int cmd
, struct sockaddr_inarp
*dst
, struct sockaddr_dl
*sdl
)
723 struct sockaddr_in so_mask
, *so_mask_ptr
= &so_mask
;
728 struct rt_msghdr m_rtm
;
732 struct rt_msghdr
*rtm
= &m_rtmsg
.m_rtm
;
733 char *cp
= m_rtmsg
.m_space
;
735 if (s
< 0) { /* first time: open socket, get pid */
736 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
741 bzero(&so_mask
, sizeof(so_mask
));
743 so_mask
.sin_addr
.s_addr
= 0xffffffff;
747 * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer
748 * appropriately (except for the mask set just above).
750 if (cmd
== RTM_DELETE
)
752 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
753 rtm
->rtm_flags
= flags
;
754 rtm
->rtm_version
= RTM_VERSION
;
757 * Note: On RTM_GET the kernel will return a scoped route when both a scoped route and
758 * a unscoped route exist. That means we cannot delete a unscoped route if there is
759 * also a matching scope route
762 rtm
->rtm_index
= ifscope
;
763 rtm
->rtm_flags
|= RTF_IFSCOPE
;
768 errx(1, "internal wrong cmd");
770 rtm
->rtm_addrs
|= RTA_GATEWAY
;
771 rtm
->rtm_rmx
.rmx_expire
= expire_time
;
772 rtm
->rtm_inits
= RTV_EXPIRE
;
773 rtm
->rtm_flags
|= (RTF_HOST
| RTF_STATIC
);
777 dst
->sin_other
= SIN_PROXY
;
779 rtm
->rtm_addrs
|= RTA_NETMASK
;
780 rtm
->rtm_flags
&= ~RTF_HOST
;
785 rtm
->rtm_addrs
|= RTA_DST
;
787 #define NEXTADDR(w, s) \
788 if ((s) != NULL && rtm->rtm_addrs & (w)) { \
789 bcopy((s), cp, sizeof(*(s))); cp += SA_SIZE(s);}
791 NEXTADDR(RTA_DST
, dst
);
792 NEXTADDR(RTA_GATEWAY
, sdl
);
793 NEXTADDR(RTA_NETMASK
, so_mask_ptr
);
795 rtm
->rtm_msglen
= cp
- (char *)&m_rtmsg
;
798 rtm
->rtm_seq
= ++seq
;
800 if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
801 if (errno
!= ESRCH
|| cmd
!= RTM_DELETE
) {
802 warn("writing to routing socket");
807 l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
808 } while (l
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= pid
));
810 warn("read from routing socket");
815 * get_ether_addr - get the hardware address of an interface on the
816 * the same subnet as ipaddr.
821 get_ether_addr(in_addr_t ipaddr
, struct ether_addr
*hwaddr
)
823 struct ifreq
*ifr
, *ifend
, *ifp
;
825 struct sockaddr_dl
*dla
;
828 struct ifreq ifs
[MAX_IFS
];
832 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
836 ifc
.ifc_len
= sizeof(ifs
);
838 if (ioctl(sock
, SIOCGIFCONF
, &ifc
) < 0) {
839 warnx("ioctl(SIOCGIFCONF)");
844 ((struct ifreq *)((char *)&(i)->ifr_addr \
845 + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) )
848 * Scan through looking for an interface with an Internet
849 * address on the same subnet as `ipaddr'.
851 ifend
= (struct ifreq
*)(ifc
.ifc_buf
+ ifc
.ifc_len
);
852 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= NEXTIFR(ifr
) ) {
853 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
855 strncpy(ifreq
.ifr_name
, ifr
->ifr_name
,
856 sizeof(ifreq
.ifr_name
));
857 ifreq
.ifr_addr
= ifr
->ifr_addr
;
859 * Check that the interface is up,
860 * and not point-to-point or loopback.
862 if (ioctl(sock
, SIOCGIFFLAGS
, &ifreq
) < 0)
864 if ((ifreq
.ifr_flags
&
865 (IFF_UP
|IFF_BROADCAST
|IFF_POINTOPOINT
|
866 IFF_LOOPBACK
|IFF_NOARP
))
867 != (IFF_UP
|IFF_BROADCAST
))
870 * Get its netmask and check that it's on
873 if (ioctl(sock
, SIOCGIFNETMASK
, &ifreq
) < 0)
875 mask
= ((struct sockaddr_in
*)
876 &ifreq
.ifr_addr
)->sin_addr
.s_addr
;
877 ina
= ((struct sockaddr_in
*)
878 &ifr
->ifr_addr
)->sin_addr
.s_addr
;
879 if ((ipaddr
& mask
) == (ina
& mask
))
880 break; /* ok, we got it! */
887 * Now scan through again looking for a link-level address
888 * for this interface.
891 for (ifr
= ifc
.ifc_req
; ifr
< ifend
; ifr
= NEXTIFR(ifr
))
892 if (strcmp(ifp
->ifr_name
, ifr
->ifr_name
) == 0 &&
893 ifr
->ifr_addr
.sa_family
== AF_LINK
)
898 * Found the link-level address - copy it out
900 dla
= (struct sockaddr_dl
*) &ifr
->ifr_addr
;
901 memcpy(hwaddr
, LLADDR(dla
), dla
->sdl_alen
);
902 printf("using interface %s for proxy with address ",
904 printf("%s\n", ether_ntoa(hwaddr
));
905 retval
= dla
->sdl_alen
;