source: MondoRescue/branches/3.3/mindi-busybox/networking/arp.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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