2 * rarp This file contains an implementation of the command
3 * that maintains the kernel's RARP cache. It is derived
4 * from Fred N. van Kempen's arp command.
6 * Version: $Id: rarp.c,v 1.9 2007/12/02 02:19:52 ecki Exp $
8 * Usage: rarp -d hostname Delete entry
9 * rarp -s hostname ethernet_address Add entry
10 * rarp -a Print entries
11 * rarp -f Add frop /etc/ethers
13 * Rewritten: Phil Blundell <Philip.Blundell@pobox.com> 1997-08-03
14 * gettext instead of catgets: Arnaldo Carvalho de Melo <acme@conectiva.com.br> 1998-06-29
15 * 1998-01-01 Bernd Eckenfels reorganised usage()
16 * 2001-04-04 Arnaldo Carvalho de Melo - use setlocale
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
26 #include <net/if_arp.h>
36 #define DFLT_HW "ether"
40 #include "net-support.h"
42 #include "pathnames.h"
45 static char no_rarp_message[] = N_("This kernel does not support RARP.\n");
47 static char version_string[] = RELEASE "\nrarp 1.03 (2001-04-04)\n";
49 static struct hwtype *hardware = NULL;
51 /* Delete an entry from the RARP cache. */
52 static int rarp_delete(int fd, struct hostent *hp)
55 struct sockaddr_in *si;
56 unsigned int found = 0;
59 /* The host can have more than one address, so we loop on them. */
60 for (addr = hp->h_addr_list; *addr != NULL; addr++) {
61 memset((char *) &req, 0, sizeof(req));
62 si = (struct sockaddr_in *) &req.arp_pa;
63 si->sin_family = hp->h_addrtype;
64 memcpy((char *) &si->sin_addr, *addr, hp->h_length);
66 /* Call the kernel. */
67 if (ioctl(fd, SIOCDRARP, &req) == 0) {
74 fputs(_(no_rarp_message), stderr);
84 printf(_("no RARP entry for %s.\n"), hp->h_name);
89 /* Set an entry in the RARP cache. */
90 static int rarp_set(int fd, struct hostent *hp, char *hw_addr)
93 struct sockaddr_in *si;
96 if (hardware->input(hw_addr, &sap)) {
97 fprintf(stderr, _("%s: bad hardware address\n"), hw_addr);
100 /* Clear and fill in the request block. */
101 memset((char *) &req, 0, sizeof(req));
102 si = (struct sockaddr_in *) &req.arp_pa;
103 si->sin_family = hp->h_addrtype;
104 memcpy((char *) &si->sin_addr, hp->h_addr_list[0], hp->h_length);
105 req.arp_ha.sa_family = hardware->type;
106 memcpy(req.arp_ha.sa_data, sap.sa_data, hardware->alen);
108 /* Call the kernel. */
109 if (ioctl(fd, SIOCSRARP, &req) < 0) {
111 fputs(_(no_rarp_message), stderr);
119 /* Process an EtherFile */
120 static int rarp_file(int fd, const char *name)
128 if ((fp = fopen(name, "r")) == NULL) {
129 fprintf(stderr, _("rarp: cannot open file %s:%s.\n"), name, strerror(errno));
132 /* Read the lines in the file. */
134 while (fgets(buff, sizeof(buff), fp)) {
136 if (buff[0] == '#' || buff[0] == '\0')
138 if ((addr = strtok(buff, "\n \t")) == NULL)
140 if ((host = strtok(NULL, "\n \t")) == NULL) {
141 fprintf(stderr, _("rarp: format error at %s:%u\n"), name, linenr);
144 if ((hp = gethostbyname(host)) == NULL) {
145 fprintf(stderr, _("rarp: %s: unknown host\n"), host);
147 if (rarp_set(fd, hp, addr) != 0) {
148 fprintf(stderr, _("rarp: cannot set entry from %s:%u\n"), name, linenr);
156 static int display_cache(void)
158 FILE *fd = proc_fopen(_PATH_PROCNET_RARP);
162 fputs(_(no_rarp_message), stderr);
164 perror(_PATH_PROCNET_RARP);
167 while (feof(fd) == 0) {
168 if (fgets(buffer, 255, fd))
169 fputs(buffer, stdout);
175 static void usage(void)
177 fprintf(stderr, _("Usage: rarp -a list entries in cache.\n"));
178 fprintf(stderr, _(" rarp -d <hostname> delete entry from cache.\n"));
179 fprintf(stderr, _(" rarp [<HW>] -s <hostname> <hwaddr> add entry to cache.\n"));
180 fprintf(stderr, _(" rarp -f add entries from /etc/ethers.\n"));
181 fprintf(stderr, _(" rarp -V display program version.\n\n"));
183 fprintf(stderr, _(" <HW>=Use '-H <hw>' to specify hardware address type. Default: %s\n"), DFLT_HW);
184 fprintf(stderr, _(" List of possible hardware types (which support ARP):\n"));
185 print_hwlist(1); /* 1 = ARPable */
189 #define MODE_DISPLAY 1
190 #define MODE_DELETE 2
192 #define MODE_ETHERS 4
194 static struct option longopts[] =
196 {"version", 0, NULL, 'V'},
197 {"verbose", 0, NULL, 'v'},
198 {"list", 0, NULL, 'a'},
199 {"set", 0, NULL, 's'},
200 {"delete", 0, NULL, 'd'},
201 {"help", 0, NULL, 'h'},
205 int main(int argc, char **argv)
207 int result = 0, mode = 0, c, nargs = 0, verbose = 0;
213 setlocale (LC_ALL, "");
214 bindtextdomain("net-tools", "/usr/share/locale");
215 textdomain("net-tools");
218 /* Get a default hardware type. */
219 hardware = get_hwtype(DFLT_HW);
222 c = getopt_long(argc, argv, "-ht:aHdsVvf", longopts, NULL);
229 fputs(version_string, stderr);
239 fprintf(stderr, _("%s: illegal option mix.\n"), argv[0]);
242 mode = (c == 'a' ? MODE_DISPLAY : (c == 'd' ? MODE_DELETE : MODE_SET));
251 hardware = get_hwtype(optarg);
261 args[nargs++] = optarg;
269 if (hardware == NULL) {
270 fprintf(stderr, _("rarp: %s: unknown hardware type.\n"), optarg);
278 if (nargs != (mode - 1)) {
281 result = display_cache();
286 if (nargs != (mode - 1)) {
289 if ((hp = gethostbyname(args[0])) == NULL) {
290 fprintf(stderr, _("rarp: %s: unknown host\n"), args[0]);
293 if (fd = socket(PF_INET, SOCK_DGRAM, 0), fd < 0) {
297 result = (mode == MODE_DELETE) ? rarp_delete(fd, hp) : rarp_set(fd, hp, args[1]);
302 if (nargs != 0 && nargs != 1)
304 if (fd = socket(PF_INET, SOCK_DGRAM, 0), fd < 0) {
308 result = rarp_file(fd, nargs ? args[0] : _PATH_ETHERS);