nameif crash for long interface names (RHBZ #209120)
[platform/upstream/net-tools.git] / rarp.c
1 /*
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.
5  *
6  * Version:     $Id: rarp.c,v 1.9 2007/12/02 02:19:52 ecki Exp $
7  *
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
12  *
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
17  *
18  */
19
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>
25 #include <net/if.h>
26 #include <net/if_arp.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <netdb.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <getopt.h>
35
36 #define DFLT_HW "ether"
37
38 #include "config.h"
39 #include "intl.h"
40 #include "net-support.h"
41 #include "version.h"
42 #include "pathnames.h"
43 #include "proc.h"
44
45 static char no_rarp_message[] = N_("This kernel does not support RARP.\n");
46
47 static char version_string[] = RELEASE "\nrarp 1.03 (2001-04-04)\n";
48
49 static struct hwtype *hardware = NULL;
50
51 /* Delete an entry from the RARP cache. */
52 static int rarp_delete(int fd, struct hostent *hp)
53 {
54     struct arpreq req;
55     struct sockaddr_in *si;
56     unsigned int found = 0;
57     char **addr;
58
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);
65
66         /* Call the kernel. */
67         if (ioctl(fd, SIOCDRARP, &req) == 0) {
68             found++;
69         } else {
70             switch (errno) {
71             case ENXIO:
72                 break;
73             case ENODEV:
74                 fputs(_(no_rarp_message), stderr);
75                 return 1;
76             default:
77                 perror("SIOCDRARP");
78                 return 1;
79             }
80         }
81     }
82
83     if (found == 0)
84         printf(_("no RARP entry for %s.\n"), hp->h_name);
85     return 0;
86 }
87
88
89 /* Set an entry in the RARP cache. */
90 static int rarp_set(int fd, struct hostent *hp, char *hw_addr)
91 {
92     struct arpreq req;
93     struct sockaddr_in *si;
94     struct sockaddr sap;
95
96     if (hardware->input(hw_addr, &sap)) {
97         fprintf(stderr, _("%s: bad hardware address\n"), hw_addr);
98         return 1;
99     }
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);
107
108     /* Call the kernel. */
109     if (ioctl(fd, SIOCSRARP, &req) < 0) {
110         if (errno == ENODEV)
111             fputs(_(no_rarp_message), stderr);
112         else
113             perror("SIOCSRARP");
114         return 1;
115     }
116     return 0;
117 }
118
119 /* Process an EtherFile */
120 static int rarp_file(int fd, const char *name)
121 {
122     char buff[1024];
123     char *host, *addr;
124     int linenr;
125     FILE *fp;
126     struct hostent *hp;
127
128     if ((fp = fopen(name, "r")) == NULL) {
129         fprintf(stderr, _("rarp: cannot open file %s:%s.\n"), name, strerror(errno));
130         return -1;
131     }
132     /* Read the lines in the file. */
133     linenr = 0;
134     while (fgets(buff, sizeof(buff), fp)) {
135         ++linenr;
136         if (buff[0] == '#' || buff[0] == '\0')
137             continue;
138         if ((addr = strtok(buff, "\n \t")) == NULL)
139             continue;
140         if ((host = strtok(NULL, "\n \t")) == NULL) {
141             fprintf(stderr, _("rarp: format error at %s:%u\n"), name, linenr);
142             continue;
143         }
144         if ((hp = gethostbyname(host)) == NULL) {
145             fprintf(stderr, _("rarp: %s: unknown host\n"), host);
146         }
147         if (rarp_set(fd, hp, addr) != 0) {
148             fprintf(stderr, _("rarp: cannot set entry from %s:%u\n"), name, linenr);
149         }
150     }
151
152     (void) fclose(fp);
153     return 0;
154 }
155
156 static int display_cache(void)
157 {
158     FILE *fd = proc_fopen(_PATH_PROCNET_RARP);
159     char buffer[256];
160     if (fd == NULL) {
161         if (errno == ENOENT)
162             fputs(_(no_rarp_message), stderr);
163         else
164             perror(_PATH_PROCNET_RARP);
165         return 1;
166     }
167     while (feof(fd) == 0) {
168         if (fgets(buffer, 255, fd))
169             fputs(buffer, stdout);
170     }
171     fclose(fd);
172     return 0;
173 }
174
175 static void usage(void)
176 {
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"));
182
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 */
186     exit(E_USAGE);
187 }
188
189 #define MODE_DISPLAY   1
190 #define MODE_DELETE    2
191 #define MODE_SET       3
192 #define MODE_ETHERS    4
193
194 static struct option longopts[] =
195 {
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'},
202     {NULL, 0, NULL, 0}
203 };
204
205 int main(int argc, char **argv)
206 {
207     int result = 0, mode = 0, c, nargs = 0, verbose = 0;
208     char *args[3];
209     struct hostent *hp;
210     int fd;
211
212 #if I18N
213     setlocale (LC_ALL, "");
214     bindtextdomain("net-tools", "/usr/share/locale");
215     textdomain("net-tools");
216 #endif
217
218     /* Get a default hardware type.  */
219     hardware = get_hwtype(DFLT_HW);
220
221     do {
222         c = getopt_long(argc, argv, "-ht:aHdsVvf", longopts, NULL);
223         switch (c) {
224         case EOF:
225             break;
226         case 'h':
227             usage();
228         case 'V':
229             fputs(version_string, stderr);
230             exit(E_VERSION);
231             break;
232         case 'v':
233             verbose++;
234             break;
235         case 'a':
236         case 's':
237         case 'd':
238             if (mode) {
239                 fprintf(stderr, _("%s: illegal option mix.\n"), argv[0]);
240                 usage();
241             } else {
242                 mode = (c == 'a' ? MODE_DISPLAY : (c == 'd' ? MODE_DELETE : MODE_SET));
243             }
244             break;
245         case 'f':
246             mode = MODE_ETHERS;
247             break;
248         case 'H':
249         case 't':
250             if (optarg) {
251                 hardware = get_hwtype(optarg);
252             } else {
253                 usage();
254             }
255             break;
256         case 1:
257             if (nargs == 2) {
258                 usage();
259                 exit(1);
260             } else {
261                 args[nargs++] = optarg;
262             }
263             break;
264         default:
265             usage();
266         }
267     } while (c != EOF);
268
269     if (hardware == NULL) {
270         fprintf(stderr, _("rarp: %s: unknown hardware type.\n"), optarg);
271         exit(1);
272     }
273     switch (mode) {
274     case 0:
275         usage();
276
277     case MODE_DISPLAY:
278         if (nargs != (mode - 1)) {
279             usage();
280         }
281         result = display_cache();
282         break;
283
284     case MODE_DELETE:
285     case MODE_SET:
286         if (nargs != (mode - 1)) {
287             usage();
288         }
289         if ((hp = gethostbyname(args[0])) == NULL) {
290             fprintf(stderr, _("rarp: %s: unknown host\n"), args[0]);
291             exit(1);
292         }
293         if (fd = socket(PF_INET, SOCK_DGRAM, 0), fd < 0) {
294             perror("socket");
295             exit(1);
296         }
297         result = (mode == MODE_DELETE) ? rarp_delete(fd, hp) : rarp_set(fd, hp, args[1]);
298         close(fd);
299         break;
300
301     case MODE_ETHERS:
302         if (nargs != 0 && nargs != 1)
303             usage();
304         if (fd = socket(PF_INET, SOCK_DGRAM, 0), fd < 0) {
305             perror("socket");
306             exit(1);
307         }
308         result = rarp_file(fd, nargs ? args[0] : _PATH_ETHERS);
309         close(fd);
310
311     }
312     exit(result);
313 }