2 * arp This file contains an implementation of the command
3 * that maintains the kernel's ARP cache. It is derived
4 * from Berkeley UNIX arp(8), but cleaner and with sup-
5 * port for devices other than Ethernet.
7 * NET-TOOLS A collection of programs that form the base set of the
8 * NET-3 Networking Distribution for the LINUX operating
11 * Version: arp 1.83 (1998-02-13)
13 * Maintainer: Bernd 'eckes' Eckenfels, <net-tools@lina.inka.de>
15 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
18 * (based on work from Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>)
19 * Alan Cox : modified for NET3
20 * Andrew Tridgell : proxy arp netmasks
21 * Bernd Eckenfels : -n option
22 * Bernd Eckenfels : Use only /proc for display
23 * {1.60} Bernd Eckenfels : new arpcode (-i) for 1.3.42 but works
25 * {1.61} Bernd Eckenfels : more verbose messages
26 * {1.62} Bernd Eckenfels : check -t for hw adresses and try to
27 * explain EINVAL (jeff)
28 *970125 {1.63} Bernd Eckenfels : -a print hardwarename instead of tiltle
29 *970201 {1.64} Bernd Eckenfels : net-features.h support
30 *970203 {1.65} Bernd Eckenfels : "#define" in "#if",
31 * -H|-A additional to -t|-p
32 *970214 {1.66} Bernd Eckenfels : Fix optarg required for -H and -A
33 *970412 {1.67} Bernd Eckenfels : device=""; is default
34 *970514 {1.68} Bernd Eckenfels : -N and -D
35 *970517 {1.69} Bernd Eckenfels : usage() fixed
36 *970622 {1.70} Bernd Eckenfels : arp -d priv
37 *970106 {1.80} Bernd Eckenfels : new syntax without -D and with "dev <If>",
38 * ATF_MAGIC, ATF_DONTPUB support.
39 * Typo fix (Debian Bug#5728 Giuliano Procida)
40 *970803 {1.81} Bernd Eckenfels : removed junk comment line 1
41 *970925 {1.82} Bernd Eckenfels : include fix for libc6
42 *980213 (1.83) Phil Blundell: set ATF_COM on new entries
43 *980629 (1.84) Arnaldo Carvalho de Melo: gettext instead of catgets
46 * This program is free software; you can redistribute it
47 * and/or modify it under the terms of the GNU General
48 * Public License as published by the Free Software
49 * Foundation; either version 2 of the License, or (at
50 * your option) any later version.
52 #include <sys/types.h>
53 #include <sys/socket.h>
54 #include <sys/ioctl.h>
56 /* #include <linux/netdevice.h> */
57 /* #include <linux/if_arp.h> */
58 #include <net/if_arp.h>
67 #include "net-support.h"
68 #include "pathnames.h"
73 #define DFLT_AF "inet"
74 #define DFLT_HW "ether"
77 #include "lib/net-features.h"
79 char *Release = RELEASE,
80 *Version = "arp 1.84 (1998-06-29)";
82 int opt_n = 0; /* do not resolve addresses */
83 int opt_N = 0; /* use symbolic names */
84 int opt_v = 0; /* debugging output flag */
85 int opt_D = 0; /* HW-address is devicename */
86 int opt_e = 0; /* 0=BSD output, 1=new linux */
87 int opt_a = 0; /* all entries, substring match */
88 struct aftype *ap; /* current address family */
89 struct hwtype *hw; /* current hardware type */
90 int sockfd=0; /* active socket descriptor */
91 int hw_set = 0; /* flag if hw-type was set (-H) */
92 char device[16]=""; /* current device */
93 static void usage(void);
95 /* Delete an entry from the ARP cache. */
105 memset((char *) &req, 0, sizeof(req));
107 /* Resolve the host name. */
109 fprintf(stderr, _("arp: need host name\n"));
112 host[(sizeof host)-1] = 0;
113 strncpy(host, *args, (sizeof host)-1);
114 if (ap->input(0, host, &sa) < 0) {
119 /* If a host has more than one address, use the correct one! */
120 memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
123 req.arp_ha.sa_family=hw->type;
125 req.arp_flags=ATF_PERM;
127 while (*args != NULL) {
128 if (opt_v) fprintf(stderr,"args=%s\n",*args);
129 if (! strcmp(*args, "pub")) {
134 if (! strcmp(*args, "priv")) {
139 if (! strcmp(*args, "temp")) {
140 req.arp_flags &= ~ATF_PERM;
144 if (! strcmp(*args, "trail")) {
145 req.arp_flags |= ATF_USETRAILERS;
149 if (! strcmp(*args, "dontpub")) {
150 #ifdef HAVE_ATF_DONTPUB
151 req.arp_flags |= ATF_DONTPUB;
153 ENOSUPP("arp", "ATF_DONTPUB");
158 if (! strcmp(*args, "auto")) {
159 #ifdef HAVE_ATF_MAGIC
160 req.arp_flags |= ATF_MAGIC;
162 ENOSUPP("arp", "ATF_MAGIC");
167 if (! strcmp(*args, "dev")) {
168 if (*++args == NULL) usage();
169 strncpy(device,*args,sizeof(device)-1);
170 device[sizeof(device)-1]='\0';
174 if (! strcmp(*args, "netmask")) {
175 if (*++args == NULL) usage();
176 if (strcmp(*args,"255.255.255.255") != 0) {
178 if (ap->input(0, host, &sa) < 0) {
182 memcpy((char *) &req.arp_netmask, (char *) &sa,
183 sizeof(struct sockaddr));
184 req.arp_flags |= ATF_NETMASK;
194 strcpy(req.arp_dev,device);
198 /* Call the kernel. */
200 if (opt_v) fprintf(stderr,"arp: SIOCDARP(nopub)\n");
201 if ((err = ioctl(sockfd, SIOCDARP, &req) < 0)) {
202 if (errno == ENXIO) {
205 printf(_("No ARP entry for %s\n"), host);
208 perror("SIOCDARP(priv)");
212 if ((flags & 1) && (err)) {
214 req.arp_flags |= ATF_PUBL;
215 if (opt_v) fprintf(stderr,"arp: SIOCDARP(pub)\n");
216 if (ioctl(sockfd, SIOCDARP, &req) < 0) {
217 if (errno == ENXIO) {
218 printf(_("No ARP entry for %s\n"), host);
221 perror("SIOCDARP(pub)");
229 /* Get the hardware address to a specified interface name */
231 arp_getdevhw(char *ifname, struct sockaddr *sa, struct hwtype *hw)
236 strcpy(ifr.ifr_name, ifname);
237 if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
238 fprintf(stderr,"arp: cant get HW-Address for `%s': %s.\n", ifname, strerror(errno));
241 if (hw && (ifr.ifr_hwaddr.sa_family!=hw->type)) {
242 fprintf(stderr,"arp: protocol type missmatch.\n");
245 memcpy((char *)sa, (char *)&(ifr.ifr_hwaddr), sizeof(struct sockaddr));
248 if (!(xhw = get_hwntype(ifr.ifr_hwaddr.sa_family)) || (xhw->sprint==0)) {
249 xhw = get_hwntype(-1);
251 fprintf(stderr, "arp: device `%s' has HW address %s `%s'.\n",ifname, xhw->name, xhw->sprint(&ifr.ifr_hwaddr));
256 /* Set an entry in the ARP cache. */
265 memset((char *) &req, 0, sizeof(req));
267 /* Resolve the host name. */
269 fprintf(stderr, _("arp: need host name\n"));
272 host[(sizeof host)-1] = 0;
273 strncpy(host, *args++, (sizeof host)-1);
274 if (ap->input(0, host, &sa) < 0) {
279 /* If a host has more than one address, use the correct one! */
280 memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
282 /* Fetch the hardware address. */
284 fprintf(stderr, _("arp: need hardware address\n"));
289 if (arp_getdevhw(*args++, &req.arp_ha, hw_set?hw:NULL) < 0)
292 if (hw->input(*args++, &req.arp_ha) < 0) {
293 fprintf(stderr, _("arp: invalid hardware address\n"));
298 /* Check out any modifiers. */
299 flags = ATF_PERM | ATF_COM;
300 while (*args != NULL) {
301 if (! strcmp(*args, "temp")) {
306 if (! strcmp(*args, "pub")) {
311 if (! strcmp(*args, "priv")) {
316 if (! strcmp(*args, "trail")) {
317 flags |= ATF_USETRAILERS;
321 if (! strcmp(*args, "dontpub")) {
322 #ifdef HAVE_ATF_DONTPUB
323 flags |= ATF_DONTPUB;
325 ENOSUPP("arp", "ATF_DONTPUB");
331 if (! strcmp(*args, "auto")) {
332 #ifdef HAVE_ATF_MAGIC
335 ENOSUPP("arp", "ATF_MAGIC");
340 if (! strcmp(*args, "dev")) {
341 if (*++args == NULL) usage();
342 strncpy(device,*args,sizeof(device)-1);
343 device[sizeof(device)-1]='\0';
348 if (! strcmp(*args, "netmask")) {
349 if (*++args == NULL) usage();
350 if (strcmp(*args,"255.255.255.255") != 0) {
352 if (ap->input(0, host, &sa) < 0) {
356 memcpy((char *) &req.arp_netmask, (char *) &sa,
357 sizeof(struct sockaddr));
358 flags |= ATF_NETMASK;
366 /* Fill in the remainder of the request. */
367 req.arp_flags = flags;
369 strcpy(req.arp_dev,device);
371 /* Call the kernel. */
372 if (opt_v) fprintf(stderr,"arp: SIOCSARP()\n");
373 if (ioctl(sockfd, SIOCSARP, &req) < 0) {
374 if (errno != EINVAL) {
384 /* Process an EtherFile */
393 if ((fp = fopen(name, "r")) == NULL) {
394 fprintf(stderr, _("arp: cannot open etherfile %s !\n"), name);
398 /* Read the lines in the file. */
400 while (fgets(buff, sizeof(buff), fp) != (char *)NULL) {
402 if (opt_v == 1) fprintf(stderr, ">> %s", buff);
403 if ((sp = strchr(buff, '\n')) != (char *)NULL) *sp = '\0';
404 if (buff[0] == '#' || buff[0] == '\0') continue;
406 argc = getargs(buff, args);
408 fprintf(stderr, _("arp: format error on line %u of etherfile %s !\n"),
413 if (arp_set(args) != 0)
414 fprintf(stderr, _("arp: cannot set entry on line %u of etherfile %s !\n"),
423 /* Print the contents of an ARP request block. */
425 arp_disp_2(char *name,int type,int arp_flags,char *hwa,char *mask,char *dev)
427 static int title = 0;
431 xhw = get_hwntype(type);
433 xhw = get_hwtype(DFLT_HW);
436 printf(_("Address\t\t\tHWtype\tHWaddress\t Flags Mask\t\t Iface\n"));
438 /* Setup the flags. */
440 if (arp_flags & ATF_COM) strcat(flags, "C");
441 if (arp_flags & ATF_PERM) strcat(flags, "M");
442 if (arp_flags & ATF_PUBL) strcat(flags, "P");
443 #ifdef HAVE_ATF_MAGIC
444 if (arp_flags & ATF_MAGIC) strcat(flags, "A");
446 #ifdef HAVE_ATF_DONTPUB
447 if (arp_flags & ATF_DONTPUB) strcat(flags, "!");
449 if (arp_flags & ATF_USETRAILERS) strcat(flags, "T");
451 if (!(arp_flags & ATF_NETMASK)) mask="";
453 printf("%-23.23s\t", name);
455 if (!(arp_flags & ATF_COM)) {
456 if (arp_flags & ATF_PUBL)
457 printf("%-8.8s%-20.20s","*","*");
459 printf("%-8.8s%-20.20s","","(incomplete)");
461 printf("%-8.8s%-20.20s", xhw->name, hwa);
464 printf("%-6.6s%-15.15s %s\n", flags,mask,dev);
467 /* Print the contents of an ARP request block. */
469 arp_disp(char *name, char *ip, int type,int arp_flags,char *hwa,char *mask,char *dev)
473 xhw = get_hwntype(type);
475 xhw = get_hwtype(DFLT_HW);
479 printf("%s (%s) at ", name, ip);
481 if (!(arp_flags & ATF_COM)) {
482 if (arp_flags & ATF_PUBL)
485 printf("<incomplete> ");
487 printf("%s [%s] ", hwa, xhw->name);
490 if (arp_flags & ATF_NETMASK)
491 printf("netmask %s ", mask);
493 if (arp_flags & ATF_PERM) printf("PERM ");
494 if (arp_flags & ATF_PUBL) printf("PUP ");
495 #ifdef HAVE_ATF_MAGIC
496 if (arp_flags & ATF_MAGIC) printf("AUTO ");
498 #ifdef HAVE_ATF_DONTPUB
499 if (arp_flags & ATF_DONTPUB) printf("DONTPUB ");
501 if (arp_flags & ATF_USETRAILERS) printf("TRAIL ");
503 printf("on %s\n", dev);
507 /* Display the contents of the ARP cache in the kernel. */
521 int num,entries=0,showed=0;
526 /* Resolve the host name. */
527 host[(sizeof host)-1] = 0;
528 strncpy(host, name, (sizeof host)-1);
529 if (ap->input(0, host, &sa) < 0) {
533 strcpy(host,ap->sprint(&sa, 1));
536 /* Open the PROCps kernel table. */
537 if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL) {
538 perror(_PATH_PROCNET_ARP);
542 /* Bypass header -- read until newline */
543 if (fgets(line, sizeof(line), fp) != (char *)NULL) {
546 /* Read the ARP cache entries. */
547 for(;fgets(line,sizeof(line),fp);)
549 num=sscanf(line,"%s 0x%x 0x%x %100s %100s %100s\n",
550 ip,&type,&flags,hwa,mask,dev);
555 /* if the user specified hw-type differs, skip it */
556 if (hw_set && (type != hw->type))
559 /* if the user specified address differs, skip it */
560 if (host[0] && strcmp(ip,host))
563 /* if the user specified device differs, skip it */
564 if (device[0] && strcmp(dev,device))
568 /* This IS ugly but it works -be */
572 if (ap->input(0, ip,&sa) < 0)
575 hostname = ap->sprint(&sa, opt_n | 0x8000);
576 if (strcmp(hostname, ip)==0)
581 arp_disp_2(hostname[0]=='?'?ip:hostname,type,flags,hwa,mask,dev);
583 arp_disp(hostname,ip,type,flags,hwa,mask,dev);
587 printf(_("Entries: %d\tSkipped: %d\tFound: %d\n"),entries,entries-showed,showed);
590 if (host[0] && !opt_a)
591 printf("%s (%s) -- no entry\n", name, host);
592 else if (hw_set || host[0] || device[0]) {
593 printf(_("arp: in %d entries no match found.\n"),entries);
603 fprintf(stderr, "%s\n%s\n%s\n",Release,Version,Features);
610 fprintf(stderr, _("Usage: arp [-vn] [-H type] [-i if] -a [hostname]\n"));
611 fprintf(stderr, _(" arp [-v] [-i if] -d hostname [pub][nopub]\n"));
612 fprintf(stderr, _(" arp [-v] [-H type] [-i if] -s hostname hw_addr [temp][nopub]\n"));
613 fprintf(stderr, _(" arp [-v] [-H type] [-i if] -s hostname hw_addr [netmask nm] pub\n"));
614 fprintf(stderr, _(" arp [-v] [-H type] [-i if] -Ds hostname if [netmask nm] pub\n"));
615 fprintf(stderr, _(" arp [-vnD] [-H type] [-i if] -f filename\n"));
620 main(int argc, char **argv)
623 struct option longopts[]=
625 {"verbose", 0, 0, 'v'},
626 {"version", 0, 0, 'V'},
628 {"delete", 0, 0, 'd'},
630 {"numeric", 0, 0, 'n'},
632 {"protocol", 1, 0, 'A'},
633 {"hw-type", 1, 0, 'H'},
634 {"device", 0, 0, 'i'},
636 {"use-device", 0, 0, 'D'},
637 {"symbolic", 0, 0, 'N'},
642 bindtextdomain("net-tools", "/usr/share/locale");
643 textdomain("net-tools");
646 /* Initialize variables... */
647 if ((hw = get_hwtype(DFLT_HW)) == NULL) {
648 fprintf(stderr, _("%s: hardware type not supported!\n"), DFLT_HW);
651 if ((ap = get_aftype(DFLT_AF)) == NULL) {
652 fprintf(stderr, _("%s: address family not supported!\n"), DFLT_AF);
657 /* Fetch the command-line arguments. */
659 while ((i = getopt_long(argc, argv, "A:H:adfp:nsei:t:vh?DNV",longopts, &lop)) != EOF) switch(i) {
686 fprintf(stderr,"arp: -N not yet supported.\n");
694 ap = get_aftype(optarg);
696 fprintf(stderr, _("arp: %s: unknown address family.\n"),
703 hw = get_hwtype(optarg);
705 fprintf(stderr, _("arp: %s: unknown hardware type.\n"),
712 strncpy(device,optarg,sizeof(device)-1);
713 device[sizeof(device)-1]='\0';
724 if (ap->af != AF_INET) {
725 fprintf(stderr, _("arp: %s: kernel only supports 'inet'.\n"),
730 fprintf(stderr, _("arp: %s: hardware type without ARP support.\n"),
734 if ((sockfd = socket(AF_INET,SOCK_DGRAM,0)) <0)
740 /* Now see what we have to do here... */
744 what = arp_show(argv[optind]);
747 case 1: /* show an ARP entry in the cache */
748 what = arp_show(argv[optind]);
751 case 2: /* process an EtherFile */
752 what = arp_file(argv[optind]);
755 case 3: /* delete an ARP entry from the cache */
756 what = arp_del(&argv[optind]);
759 case 4: /* set an ARP entry in the cache */
760 what = arp_set(&argv[optind]);