Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/networking/arp.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1123 - (hide annotations) (download)
Wed Aug 18 21:56:57 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 11709 byte(s)
-updated to busybox-1.17.1
1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * arp.c - Manipulate the system ARP cache
4     *
5     * This program is free software; you can redistribute it and/or
6     * modify it under the terms of the GNU General Public License
7     * as published by the Free Software Foundation; either version
8     * 2 of the License, or (at your option) any later version.
9     *
10     * Author: Fred N. van Kempen, <waltje at uwalt.nl.mugnet.org>
11     * Busybox port: Paul van Gool <pvangool at mimotech.com>
12     *
13     * modified for getopt32 by Arne Bernin <arne [at] alamut.de>
14     */
15    
16 niro 816 #include "libbb.h"
17 niro 532 #include "inet_common.h"
18    
19     #include <arpa/inet.h>
20     #include <net/if.h>
21     #include <net/if_arp.h>
22     #include <netinet/ether.h>
23     #include <netpacket/packet.h>
24    
25     #define DEBUG 0
26    
27     #define DFLT_AF "inet"
28     #define DFLT_HW "ether"
29    
30 niro 984 enum {
31     ARP_OPT_A = (1 << 0),
32     ARP_OPT_p = (1 << 1),
33     ARP_OPT_H = (1 << 2),
34     ARP_OPT_t = (1 << 3),
35     ARP_OPT_i = (1 << 4),
36     ARP_OPT_a = (1 << 5),
37     ARP_OPT_d = (1 << 6),
38     ARP_OPT_n = (1 << 7), /* do not resolve addresses */
39     ARP_OPT_D = (1 << 8), /* HW-address is devicename */
40     ARP_OPT_s = (1 << 9),
41     ARP_OPT_v = (1 << 10) * DEBUG, /* debugging output flag */
42     };
43 niro 532
44 niro 984 enum {
45     sockfd = 3, /* active socket descriptor */
46     };
47 niro 532
48 niro 984 struct globals {
49     const struct aftype *ap; /* current address family */
50     const struct hwtype *hw; /* current hardware type */
51     const char *device; /* current device */
52     smallint hw_set; /* flag if hw-type was set (-H) */
53 niro 532
54 niro 1123 } FIX_ALIASING;
55 niro 984 #define G (*(struct globals*)&bb_common_bufsiz1)
56     #define ap (G.ap )
57     #define hw (G.hw )
58     #define device (G.device )
59     #define hw_set (G.hw_set )
60     #define INIT_G() do { \
61     device = ""; \
62     } while (0)
63    
64    
65 niro 816 static const char options[] ALIGN1 =
66     "pub\0"
67     "priv\0"
68     "temp\0"
69     "trail\0"
70     "dontpub\0"
71     "auto\0"
72     "dev\0"
73     "netmask\0";
74 niro 532
75     /* Delete an entry from the ARP cache. */
76     /* Called only from main, once */
77     static int arp_del(char **args)
78     {
79 niro 816 char *host;
80 niro 532 struct arpreq req;
81     struct sockaddr sa;
82     int flags = 0;
83     int err;
84    
85     memset(&req, 0, sizeof(req));
86    
87     /* Resolve the host name. */
88 niro 816 host = *args;
89     if (ap->input(host, &sa) < 0) {
90 niro 532 bb_herror_msg_and_die("%s", host);
91     }
92    
93     /* If a host has more than one address, use the correct one! */
94     memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
95    
96     if (hw_set)
97     req.arp_ha.sa_family = hw->type;
98    
99     req.arp_flags = ATF_PERM;
100     args++;
101     while (*args != NULL) {
102 niro 816 switch (index_in_strings(options, *args)) {
103 niro 532 case 0: /* "pub" */
104     flags |= 1;
105     args++;
106     break;
107     case 1: /* "priv" */
108     flags |= 2;
109     args++;
110     break;
111     case 2: /* "temp" */
112     req.arp_flags &= ~ATF_PERM;
113     args++;
114     break;
115     case 3: /* "trail" */
116     req.arp_flags |= ATF_USETRAILERS;
117     args++;
118     break;
119     case 4: /* "dontpub" */
120     #ifdef HAVE_ATF_DONTPUB
121     req.arp_flags |= ATF_DONTPUB;
122     #else
123     bb_error_msg("feature ATF_DONTPUB is not supported");
124     #endif
125     args++;
126     break;
127     case 5: /* "auto" */
128     #ifdef HAVE_ATF_MAGIC
129     req.arp_flags |= ATF_MAGIC;
130     #else
131     bb_error_msg("feature ATF_MAGIC is not supported");
132     #endif
133     args++;
134     break;
135     case 6: /* "dev" */
136     if (*++args == NULL)
137     bb_show_usage();
138     device = *args;
139     args++;
140     break;
141     case 7: /* "netmask" */
142     if (*++args == NULL)
143     bb_show_usage();
144     if (strcmp(*args, "255.255.255.255") != 0) {
145 niro 816 host = *args;
146     if (ap->input(host, &sa) < 0) {
147 niro 532 bb_herror_msg_and_die("%s", host);
148     }
149     memcpy(&req.arp_netmask, &sa, sizeof(struct sockaddr));
150     req.arp_flags |= ATF_NETMASK;
151     }
152     args++;
153     break;
154     default:
155     bb_show_usage();
156     break;
157     }
158     }
159     if (flags == 0)
160     flags = 3;
161    
162     strncpy(req.arp_dev, device, sizeof(req.arp_dev));
163    
164     err = -1;
165    
166     /* Call the kernel. */
167     if (flags & 2) {
168     if (option_mask32 & ARP_OPT_v)
169     bb_error_msg("SIOCDARP(nopub)");
170     err = ioctl(sockfd, SIOCDARP, &req);
171     if (err < 0) {
172     if (errno == ENXIO) {
173     if (flags & 1)
174     goto nopub;
175     printf("No ARP entry for %s\n", host);
176     return -1;
177     }
178     bb_perror_msg_and_die("SIOCDARP(priv)");
179     }
180     }
181     if ((flags & 1) && err) {
182     nopub:
183     req.arp_flags |= ATF_PUBL;
184     if (option_mask32 & ARP_OPT_v)
185     bb_error_msg("SIOCDARP(pub)");
186     if (ioctl(sockfd, SIOCDARP, &req) < 0) {
187     if (errno == ENXIO) {
188     printf("No ARP entry for %s\n", host);
189     return -1;
190     }
191     bb_perror_msg_and_die("SIOCDARP(pub)");
192     }
193     }
194     return 0;
195     }
196    
197     /* Get the hardware address to a specified interface name */
198     static void arp_getdevhw(char *ifname, struct sockaddr *sa,
199     const struct hwtype *hwt)
200     {
201     struct ifreq ifr;
202     const struct hwtype *xhw;
203    
204     strcpy(ifr.ifr_name, ifname);
205 niro 816 ioctl_or_perror_and_die(sockfd, SIOCGIFHWADDR, &ifr,
206     "cant get HW-Address for '%s'", ifname);
207 niro 532 if (hwt && (ifr.ifr_hwaddr.sa_family != hw->type)) {
208     bb_error_msg_and_die("protocol type mismatch");
209     }
210     memcpy(sa, &(ifr.ifr_hwaddr), sizeof(struct sockaddr));
211    
212     if (option_mask32 & ARP_OPT_v) {
213     xhw = get_hwntype(ifr.ifr_hwaddr.sa_family);
214     if (!xhw || !xhw->print) {
215     xhw = get_hwntype(-1);
216     }
217     bb_error_msg("device '%s' has HW address %s '%s'",
218     ifname, xhw->name,
219 niro 816 xhw->print((unsigned char *) &ifr.ifr_hwaddr.sa_data));
220 niro 532 }
221     }
222    
223     /* Set an entry in the ARP cache. */
224     /* Called only from main, once */
225     static int arp_set(char **args)
226     {
227 niro 816 char *host;
228 niro 532 struct arpreq req;
229     struct sockaddr sa;
230     int flags;
231    
232     memset(&req, 0, sizeof(req));
233    
234 niro 816 host = *args++;
235     if (ap->input(host, &sa) < 0) {
236 niro 532 bb_herror_msg_and_die("%s", host);
237     }
238     /* If a host has more than one address, use the correct one! */
239     memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
240    
241     /* Fetch the hardware address. */
242     if (*args == NULL) {
243     bb_error_msg_and_die("need hardware address");
244     }
245     if (option_mask32 & ARP_OPT_D) {
246     arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL);
247     } else {
248     if (hw->input(*args++, &req.arp_ha) < 0) {
249     bb_error_msg_and_die("invalid hardware address");
250     }
251     }
252    
253     /* Check out any modifiers. */
254     flags = ATF_PERM | ATF_COM;
255     while (*args != NULL) {
256 niro 816 switch (index_in_strings(options, *args)) {
257 niro 532 case 0: /* "pub" */
258     flags |= ATF_PUBL;
259     args++;
260     break;
261     case 1: /* "priv" */
262     flags &= ~ATF_PUBL;
263     args++;
264     break;
265     case 2: /* "temp" */
266     flags &= ~ATF_PERM;
267     args++;
268     break;
269     case 3: /* "trail" */
270     flags |= ATF_USETRAILERS;
271     args++;
272     break;
273     case 4: /* "dontpub" */
274     #ifdef HAVE_ATF_DONTPUB
275     flags |= ATF_DONTPUB;
276     #else
277     bb_error_msg("feature ATF_DONTPUB is not supported");
278     #endif
279     args++;
280     break;
281     case 5: /* "auto" */
282     #ifdef HAVE_ATF_MAGIC
283     flags |= ATF_MAGIC;
284     #else
285     bb_error_msg("feature ATF_MAGIC is not supported");
286     #endif
287     args++;
288     break;
289     case 6: /* "dev" */
290     if (*++args == NULL)
291     bb_show_usage();
292     device = *args;
293     args++;
294     break;
295     case 7: /* "netmask" */
296     if (*++args == NULL)
297     bb_show_usage();
298     if (strcmp(*args, "255.255.255.255") != 0) {
299 niro 816 host = *args;
300     if (ap->input(host, &sa) < 0) {
301 niro 532 bb_herror_msg_and_die("%s", host);
302     }
303     memcpy(&req.arp_netmask, &sa, sizeof(struct sockaddr));
304     flags |= ATF_NETMASK;
305     }
306     args++;
307     break;
308     default:
309     bb_show_usage();
310     break;
311     }
312     }
313    
314     /* Fill in the remainder of the request. */
315     req.arp_flags = flags;
316    
317     strncpy(req.arp_dev, device, sizeof(req.arp_dev));
318    
319     /* Call the kernel. */
320     if (option_mask32 & ARP_OPT_v)
321     bb_error_msg("SIOCSARP()");
322 niro 816 xioctl(sockfd, SIOCSARP, &req);
323 niro 532 return 0;
324     }
325    
326    
327     /* Print the contents of an ARP request block. */
328     static void
329 niro 816 arp_disp(const char *name, char *ip, int type, int arp_flags,
330 niro 532 char *hwa, char *mask, char *dev)
331     {
332 niro 816 static const int arp_masks[] = {
333     ATF_PERM, ATF_PUBL,
334     #ifdef HAVE_ATF_MAGIC
335     ATF_MAGIC,
336     #endif
337     #ifdef HAVE_ATF_DONTPUB
338     ATF_DONTPUB,
339     #endif
340     ATF_USETRAILERS,
341     };
342     static const char arp_labels[] ALIGN1 = "PERM\0""PUP\0"
343     #ifdef HAVE_ATF_MAGIC
344     "AUTO\0"
345     #endif
346     #ifdef HAVE_ATF_DONTPUB
347     "DONTPUB\0"
348     #endif
349     "TRAIL\0"
350     ;
351    
352 niro 532 const struct hwtype *xhw;
353    
354     xhw = get_hwntype(type);
355     if (xhw == NULL)
356     xhw = get_hwtype(DFLT_HW);
357    
358     printf("%s (%s) at ", name, ip);
359    
360     if (!(arp_flags & ATF_COM)) {
361     if (arp_flags & ATF_PUBL)
362     printf("* ");
363     else
364     printf("<incomplete> ");
365     } else {
366     printf("%s [%s] ", hwa, xhw->name);
367     }
368    
369     if (arp_flags & ATF_NETMASK)
370     printf("netmask %s ", mask);
371    
372 niro 816 print_flags_separated(arp_masks, arp_labels, arp_flags, " ");
373     printf(" on %s\n", dev);
374 niro 532 }
375    
376     /* Display the contents of the ARP cache in the kernel. */
377     /* Called only from main, once */
378     static int arp_show(char *name)
379     {
380 niro 816 const char *host;
381     const char *hostname;
382     FILE *fp;
383 niro 532 struct sockaddr sa;
384     int type, flags;
385     int num;
386     unsigned entries = 0, shown = 0;
387 niro 816 char ip[128];
388     char hwa[128];
389     char mask[128];
390     char line[128];
391     char dev[128];
392 niro 532
393 niro 816 host = NULL;
394 niro 532 if (name != NULL) {
395     /* Resolve the host name. */
396 niro 816 if (ap->input(name, &sa) < 0) {
397     bb_herror_msg_and_die("%s", name);
398 niro 532 }
399 niro 816 host = xstrdup(ap->sprint(&sa, 1));
400 niro 532 }
401 niro 816 fp = xfopen_for_read("/proc/net/arp");
402     /* Bypass header -- read one line */
403     fgets(line, sizeof(line), fp);
404    
405     /* Read the ARP cache entries. */
406     while (fgets(line, sizeof(line), fp)) {
407    
408 niro 532 mask[0] = '-'; mask[1] = '\0';
409     dev[0] = '-'; dev[1] = '\0';
410 niro 816 /* All these strings can't overflow
411     * because fgets above reads limited amount of data */
412     num = sscanf(line, "%s 0x%x 0x%x %s %s %s\n",
413     ip, &type, &flags, hwa, mask, dev);
414     if (num < 4)
415     break;
416 niro 532
417 niro 816 entries++;
418     /* if the user specified hw-type differs, skip it */
419     if (hw_set && (type != hw->type))
420     continue;
421 niro 532
422 niro 816 /* if the user specified address differs, skip it */
423     if (host && strcmp(ip, host) != 0)
424     continue;
425 niro 532
426 niro 816 /* if the user specified device differs, skip it */
427     if (device[0] && strcmp(dev, device) != 0)
428     continue;
429 niro 532
430 niro 816 shown++;
431     /* This IS ugly but it works -be */
432     hostname = "?";
433     if (!(option_mask32 & ARP_OPT_n)) {
434     if (ap->input(ip, &sa) < 0)
435     hostname = ip;
436     else
437     hostname = ap->sprint(&sa, (option_mask32 & ARP_OPT_n) | 0x8000);
438     if (strcmp(hostname, ip) == 0)
439 niro 532 hostname = "?";
440 niro 816 }
441 niro 532
442 niro 816 arp_disp(hostname, ip, type, flags, hwa, mask, dev);
443 niro 532 }
444     if (option_mask32 & ARP_OPT_v)
445     printf("Entries: %d\tSkipped: %d\tFound: %d\n",
446     entries, entries - shown, shown);
447    
448     if (!shown) {
449 niro 816 if (hw_set || host || device[0])
450 niro 532 printf("No match found in %d entries\n", entries);
451     }
452 niro 816 if (ENABLE_FEATURE_CLEAN_UP) {
453     free((char*)host);
454     fclose(fp);
455     }
456 niro 532 return 0;
457     }
458    
459 niro 816 int arp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
460     int arp_main(int argc UNUSED_PARAM, char **argv)
461 niro 532 {
462 niro 816 const char *hw_type = "ether";
463     const char *protocol;
464 niro 984 unsigned opts;
465 niro 532
466 niro 984 INIT_G();
467    
468     xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sockfd);
469 niro 532 ap = get_aftype(DFLT_AF);
470     if (!ap)
471     bb_error_msg_and_die("%s: %s not supported", DFLT_AF, "address family");
472    
473 niro 984 opts = getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol,
474 niro 532 &hw_type, &hw_type, &device);
475     argv += optind;
476 niro 984 if (opts & (ARP_OPT_A | ARP_OPT_p)) {
477 niro 532 ap = get_aftype(protocol);
478     if (ap == NULL)
479     bb_error_msg_and_die("%s: unknown %s", protocol, "address family");
480     }
481 niro 984 if (opts & (ARP_OPT_A | ARP_OPT_p)) {
482 niro 532 hw = get_hwtype(hw_type);
483     if (hw == NULL)
484     bb_error_msg_and_die("%s: unknown %s", hw_type, "hardware type");
485     hw_set = 1;
486     }
487 niro 984 //if (opts & ARP_OPT_i)... -i
488 niro 532
489     if (ap->af != AF_INET) {
490     bb_error_msg_and_die("%s: kernel only supports 'inet'", ap->name);
491     }
492    
493     /* If no hw type specified get default */
494     if (!hw) {
495     hw = get_hwtype(DFLT_HW);
496     if (!hw)
497     bb_error_msg_and_die("%s: %s not supported", DFLT_HW, "hardware type");
498     }
499    
500     if (hw->alen <= 0) {
501     bb_error_msg_and_die("%s: %s without ARP support",
502     hw->name, "hardware type");
503     }
504    
505     /* Now see what we have to do here... */
506 niro 984 if (opts & (ARP_OPT_d | ARP_OPT_s)) {
507 niro 532 if (argv[0] == NULL)
508     bb_error_msg_and_die("need host name");
509 niro 984 if (opts & ARP_OPT_s)
510 niro 532 return arp_set(argv);
511     return arp_del(argv);
512     }
513 niro 984 //if (opts & ARP_OPT_a) - default
514 niro 532 return arp_show(argv[0]);
515     }