PATCH - arp applet (Re: [BusyBox] Adding arp to busybox)
Charlie Brady
charlieb-busybox at e-smith.com
Tue Apr 27 17:54:38 UTC 2004
On Mon, 26 Jan 2004, Paul van Gool wrote:
> I recently had to use arp on an embedded system and noticed busybox does
> not contain arp. So I added it. It's basically a port of the net-tools arp
> to busybox.
>
> This mail has two attachments:
>
> - A diff against the current busybox code to add arp
> - networking/arp.c
I've combined these into a single patch (unified diff), and ported to
1.00-pre10. Patch attached. Thanks!
--
Charlie
A: Because we read from top to bottom, left to right.
Q: Why should i start my reply below the quoted text?
-------------- next part --------------
diff -ruN busybox-1.00-pre10/include/applets.h busybox-1.00-pre10+arp/include/applets.h
--- busybox-1.00-pre10/include/applets.h 2004-04-06 12:59:43.000000000 -0400
+++ busybox-1.00-pre10+arp/include/applets.h 2004-04-26 12:02:43.000000000 -0400
@@ -63,6 +63,9 @@
#ifdef CONFIG_AR
APPLET(ar, ar_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
#endif
+#ifdef CONFIG_ARP
+ APPLET(arp, arp_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+#endif
#ifdef CONFIG_ARPING
APPLET(arping, arping_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
#endif
diff -ruN busybox-1.00-pre10/include/libbb.h busybox-1.00-pre10+arp/include/libbb.h
--- busybox-1.00-pre10/include/libbb.h 2004-03-15 03:28:38.000000000 -0500
+++ busybox-1.00-pre10+arp/include/libbb.h 2004-04-26 12:04:19.000000000 -0400
@@ -488,4 +488,36 @@
#define HASH_MD5 2
extern int hash_fd(int fd, const size_t size, const uint8_t hash_algo, uint8_t *hashval);
+/* This structure defines protocol families and their handlers. */
+struct aftype {
+ char *name;
+ char *title;
+ int af;
+ int alen;
+ char *(*print) (unsigned char *);
+ char *(*sprint) (struct sockaddr *, int numeric);
+ int (*input) (int type, char *bufp, struct sockaddr *);
+ void (*herror) (char *text);
+ int (*rprint) (int options);
+ int (*rinput) (int typ, int ext, char **argv);
+
+ /* may modify src */
+ int (*getmask) (char *src, struct sockaddr * mask, char *name);
+
+ int fd;
+ char *flag_file;
+};
+
+/* This structure defines hardware protocols and their handlers. */
+struct hwtype {
+ char *name;
+ char *title;
+ int type;
+ int alen;
+ char *(*print) (unsigned char *);
+ int (*input) (char *, struct sockaddr *);
+ int (*activate) (int fd);
+ int suppress_null_addr;
+};
+
#endif /* __LIBCONFIG_H__ */
diff -ruN busybox-1.00-pre10/include/usage.h busybox-1.00-pre10+arp/include/usage.h
--- busybox-1.00-pre10/include/usage.h 2004-04-13 15:27:20.000000000 -0400
+++ busybox-1.00-pre10+arp/include/usage.h 2004-04-26 12:08:37.000000000 -0400
@@ -45,6 +45,28 @@
"\t-x\t\textract\n" \
"\t-v\t\tverbosely list files processed"
+#define arp_trivial_usage \
+ "[-evn] [-H type] [-i if] -a [hostname]\n" \
+ "\tarp [-v] [-i if] -d hostname [pub]\n" \
+ "\tarp [-v] [-H type] [-i if] -s hostname hw_addr [temp]\n" \
+ "\tarp [-v] [-H type] [-i if] -s hostname hw_addr [netmask nm] pub\n" \
+ "\tarp [-v] [-H type] [-i if] -Ds hostname ifa [netmask nm] pub\n" \
+ "\tarp [-vnD] [-H type] [-i if] -f [filename]\n"
+#define arp_full_usage \
+ "Manipulate the system ARP cache.\n"
+ "Options:\n" \
+ "\t-a\t\tdisplay (all) hosts in alternative (BSD) style\n" \
+ "\t-e\t\tdisplay (all) hosts in default (Linux) style\n" \
+ "\t-s\t\tset a new ARP entry\n" \
+ "\t-d\t\tdelete a specified entry\n" \
+ "\t-v\t\tbe verbose\n" \
+ "\t-n\t\tdon't resolve names\n" \
+ "\t-i if\tspecify network interface (e.g. eth0)\n" \
+ "\t-D\t\tread <hwaddr> from given device\n" \
+ "\t-A, -p\t\tspecify protocol family\n" \
+ "\t-f\t\tread new entries from file or from /etc/ethers\n" \
+ "\t-H hwtype\tto specify hardware address type\n"
+
#define arping_trivial_usage \
"[-fqbDUA] [-c count] [-w timeout] [-I device] [-s sender] target\n"
#define arping_full_usage \
diff -ruN busybox-1.00-pre10/libbb/interface.c busybox-1.00-pre10+arp/libbb/interface.c
--- busybox-1.00-pre10/libbb/interface.c 2004-03-15 03:28:42.000000000 -0500
+++ busybox-1.00-pre10+arp/libbb/interface.c 2004-04-26 16:29:25.000000000 -0400
@@ -135,26 +135,6 @@
#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
#endif
-/* This structure defines protocol families and their handlers. */
-struct aftype {
- const char *name;
- const char *title;
- int af;
- int alen;
- char *(*print) (unsigned char *);
- char *(*sprint) (struct sockaddr *, int numeric);
- int (*input) (int type, char *bufp, struct sockaddr *);
- void (*herror) (char *text);
- int (*rprint) (int options);
- int (*rinput) (int typ, int ext, char **argv);
-
- /* may modify src */
- int (*getmask) (char *src, struct sockaddr * mask, char *name);
-
- int fd;
- char *flag_file;
-};
-
#ifdef KEEP_UNUSED
static int flag_unx;
@@ -319,21 +299,22 @@
return (NULL);
return (buff);
}
+#endif /* KEEP_UNUSED */
static int INET_getsock(char *bufp, struct sockaddr *sap)
{
char *sp = bufp, *bp;
unsigned int i;
unsigned val;
- struct sockaddr_in *sin;
+ struct sockaddr_in *sock_in;
- sin = (struct sockaddr_in *) sap;
- sin->sin_family = AF_INET;
- sin->sin_port = 0;
-
- val = 0;
- bp = (char *) &val;
- for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
+ sock_in = (struct sockaddr_in *) sap;
+ sock_in->sin_family = AF_INET;
+ sock_in->sin_port = 0;
+
+ val = 0;
+ bp = (char *) &val;
+ for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
*sp = toupper(*sp);
if ((*sp >= 'A') && (*sp <= 'F'))
@@ -356,7 +337,7 @@
sp++;
}
- sin->sin_addr.s_addr = htonl(val);
+ sock_in->sin_addr.s_addr = htonl(val);
return (sp - bufp);
}
@@ -373,6 +354,7 @@
}
}
+#ifdef KEEP_UNUSED
static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
{
struct sockaddr_in *mask = (struct sockaddr_in *) m;
@@ -399,7 +381,7 @@
static struct aftype inet_aftype = {
"inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
NULL /* UNUSED INET_print */ , INET_sprint,
- NULL /* UNUSED INET_input */ , NULL /* UNUSED INET_reserror */ ,
+ INET_input, NULL /* UNUSED INET_reserror */ ,
NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
NULL /* UNUSED INET_getnetmask */ ,
-1,
@@ -440,7 +422,6 @@
return (buff);
}
-#ifdef KEEP_UNUSED
static int INET6_getsock(char *bufp, struct sockaddr *sap)
{
struct sockaddr_in6 *sin6;
@@ -464,12 +445,11 @@
return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
}
}
-#endif /* KEEP_UNUSED */
static struct aftype inet6_aftype = {
"inet6", "IPv6", AF_INET6, sizeof(struct in6_addr),
NULL /* UNUSED INET6_print */ , INET6_sprint,
- NULL /* UNUSED INET6_input */ , NULL /* UNUSED INET6_reserror */ ,
+ INET6_input, NULL /* UNUSED INET6_reserror */ ,
NULL /*INET6_rprint */ , NULL /*INET6_rinput */ ,
NULL /* UNUSED INET6_getnetmask */ ,
-1,
@@ -670,9 +650,10 @@
free(buf);
}
+#endif
/* Check our protocol family table for this family. */
-static struct aftype *get_aftype(const char *name)
+struct aftype *get_aftype(const char *name)
{
struct aftype **afp;
@@ -691,7 +672,6 @@
bb_error_msg(_("Please don't supply more than one address family."));
return (NULL);
}
-#endif /* KEEP_UNUSED */
/* Check our protocol family table for this family. */
static struct aftype *get_afntype(int af)
@@ -1349,18 +1329,6 @@
return 0;
}
-/* This structure defines hardware protocols and their handlers. */
-struct hwtype {
- const char *name;
- const char *title;
- int type;
- int alen;
- char *(*print) (unsigned char *);
- int (*input) (char *, struct sockaddr *);
- int (*activate) (int fd);
- int suppress_null_addr;
-};
-
static struct hwtype unspec_hwtype = {
"unspec", "UNSPEC", -1, 0,
UNSPEC_print, NULL, NULL
@@ -1677,7 +1645,26 @@
#endif
/* Check our hardware type table for this type. */
-static struct hwtype *get_hwntype(int type)
+struct hwtype *get_hwtype(const char *name)
+{
+ struct hwtype **hwp;
+
+#ifdef KEEP_UNUSED
+ if (!sVhwinit)
+ hwinit();
+#endif
+
+ hwp = hwtypes;
+ while (*hwp != NULL) {
+ if (!strcmp((*hwp)->name, name))
+ return (*hwp);
+ hwp++;
+ }
+ return (NULL);
+}
+
+/* Check our hardware type table for this type. */
+struct hwtype *get_hwntype(int type)
{
struct hwtype **hwp;
diff -ruN busybox-1.00-pre10/networking/arp.c busybox-1.00-pre10+arp/networking/arp.c
--- busybox-1.00-pre10/networking/arp.c 1969-12-31 19:00:00.000000000 -0500
+++ busybox-1.00-pre10+arp/networking/arp.c 2004-04-26 16:44:31.000000000 -0400
@@ -0,0 +1,757 @@
+/*
+ * arp.c - Manipulate the system ARP cache
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Author: Fred N. van Kempen, <waltje at uwalt.nl.mugnet.org>
+ * Busybox port: Paul van Gool <pvangool at mimotech.com>
+ */
+
+#include <sys/ioctl.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/ether.h>
+#include <netpacket/packet.h>
+
+#include "busybox.h"
+#include "inet_common.h"
+
+#define APPLET_NAME "arp"
+
+#define DFLT_AF "inet"
+#define DFLT_HW "ether"
+
+#define _PATH_PROCNET_ARP "/proc/net/arp"
+
+extern struct aftype *get_aftype(const char *name);
+extern struct hwtype *get_hwntype(int type);
+extern struct hwtype *get_hwtype(const char *name);
+
+int opt_n = 0; /* do not resolve addresses */
+int opt_v = 0; /* debugging output flag */
+int opt_D = 0; /* HW-address is devicename */
+int opt_e = 0; /* 0=BSD output, 1=new linux */
+int opt_a = 0; /* all entries, substring match */
+struct aftype *ap; /* current address family */
+struct hwtype *hw; /* current hardware type */
+int sockfd = 0; /* active socket descriptor */
+int hw_set = 0; /* flag if hw-type was set (-H) */
+char device[16] = ""; /* current device */
+
+/* Split the input string into multiple fields. */
+int getargs(char *string, char *arguments[])
+{
+ int len = strlen(string);
+ char temp[len+1];
+ char *sp, *ptr;
+ int i, argc;
+ char want;
+
+ /*
+ * Copy the string into a buffer. We may have to modify
+ * the original string because of all the quoting...
+ */
+ sp = string;
+ i = 0;
+ strcpy(temp, string);
+ ptr = temp;
+
+ /*
+ * Look for delimiters ("); if present whatever
+ * they enclose will be considered one argument.
+ */
+ while (*ptr != '\0' && i < 31) {
+ /* Ignore leading whitespace on input string. */
+ while (*ptr == ' ' || *ptr == '\t')
+ ptr++;
+
+ /* Set string pointer. */
+ arguments[i++] = sp;
+
+ /* Check for any delimiters. */
+ if (*ptr == '"' || *ptr == '\'') {
+ /*
+ * Copy the string up to any whitespace OR the next
+ * delimiter. If the delimiter was escaped, skip it
+ * as it if was not there.
+ */
+ want = *ptr++;
+ while (*ptr != '\0') {
+ if (*ptr == want && *(ptr - 1) != '\\') {
+ ptr++;
+ break;
+ }
+ *sp++ = *ptr++;
+ }
+ } else {
+ /* Just copy the string up to any whitespace. */
+ while (*ptr != '\0' && *ptr != ' ' && *ptr != '\t')
+ *sp++ = *ptr++;
+ }
+ *sp++ = '\0';
+
+ /* Skip trailing whitespace. */
+ if (*ptr != '\0') {
+ while (*ptr == ' ' || *ptr == '\t')
+ ptr++;
+ }
+ }
+ argc = i;
+ while (i < 32)
+ arguments[i++] = (char *) NULL;
+ return (argc);
+}
+
+/* Delete an entry from the ARP cache. */
+static int arp_del(char **args)
+{
+ char host[128];
+ struct arpreq req;
+ struct sockaddr sa;
+ int flags = 0;
+ int err;
+
+ memset((char *) &req, 0, sizeof(req));
+
+ /* Resolve the host name. */
+ if (*args == NULL) {
+ bb_error_msg("need host name\n");
+ return -1;
+ }
+
+ safe_strncpy(host, *args, (sizeof host));
+ if (ap->input(0, host, &sa) < 0) {
+ bb_herror_msg("%s", host);
+ return -1;
+ }
+
+ /* If a host has more than one address, use the correct one! */
+ memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
+
+ if (hw_set)
+ req.arp_ha.sa_family = hw->type;
+
+ req.arp_flags = ATF_PERM;
+ args++;
+ while (*args != NULL) {
+ if (opt_v)
+ bb_error_msg("args=%s\n", *args);
+ if (!strcmp(*args, "pub")) {
+ flags |= 1;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "priv")) {
+ flags |= 2;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "temp")) {
+ req.arp_flags &= ~ATF_PERM;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "trail")) {
+ req.arp_flags |= ATF_USETRAILERS;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "dontpub")) {
+#ifdef HAVE_ATF_DONTPUB
+ req.arp_flags |= ATF_DONTPUB;
+#else
+ bb_error_msg("feature ATF_DONTPUB is not supported");
+#endif
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "auto")) {
+#ifdef HAVE_ATF_MAGIC
+ req.arp_flags |= ATF_MAGIC;
+#else
+ bb_error_msg("feature ATF_MAGIC is not supported");
+#endif
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "dev")) {
+ if (*++args == NULL)
+ bb_show_usage();
+ safe_strncpy(device, *args, sizeof(device));
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "netmask")) {
+ if (*++args == NULL)
+ bb_show_usage();
+ if (strcmp(*args, "255.255.255.255") != 0) {
+ strcpy(host, *args);
+ if (ap->input(0, host, &sa) < 0) {
+ bb_herror_msg("%s", host);
+ return (-1);
+ }
+ memcpy((char *) &req.arp_netmask, (char *) &sa,
+ sizeof(struct sockaddr));
+ req.arp_flags |= ATF_NETMASK;
+ }
+ args++;
+ continue;
+ }
+ bb_show_usage();
+ }
+ if (flags == 0)
+ flags = 3;
+
+ strcpy(req.arp_dev, device);
+
+ err = -1;
+
+ /* Call the kernel. */
+ if (flags & 2) {
+ if (opt_v)
+ bb_error_msg("SIOCDARP(nopub)\n");
+ if ((err = ioctl(sockfd, SIOCDARP, &req) < 0)) {
+ if (errno == ENXIO) {
+ if (flags & 1)
+ goto nopub;
+ printf("No ARP entry for %s\n", host);
+ return -1;
+ }
+ perror("SIOCDARP(priv)");
+ return -1;
+ }
+ }
+ if ((flags & 1) && (err)) {
+ nopub:
+ req.arp_flags |= ATF_PUBL;
+ if (opt_v)
+ bb_error_msg("SIOCDARP(pub)\n");
+ if (ioctl(sockfd, SIOCDARP, &req) < 0) {
+ if (errno == ENXIO) {
+ printf("No ARP entry for %s\n", host);
+ return -1;
+ }
+ perror("SIOCDARP(pub)");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Get the hardware address to a specified interface name */
+static int arp_getdevhw(char *ifname, struct sockaddr *sa, struct hwtype *hwt)
+{
+ struct ifreq ifr;
+ struct hwtype *xhw;
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
+ bb_error_msg("cant get HW-Address for `%s': %s.\n",
+ ifname, strerror(errno));
+ return -1;
+ }
+ if (hwt && (ifr.ifr_hwaddr.sa_family != hw->type)) {
+ bb_error_msg("protocol type mismatch.\n");
+ return -1;
+ }
+ memcpy((char *) sa, (char *) &(ifr.ifr_hwaddr), sizeof(struct sockaddr));
+
+ if (opt_v) {
+ if (!(xhw = get_hwntype(ifr.ifr_hwaddr.sa_family)) ||
+ (xhw->print == 0))
+ {
+ xhw = get_hwntype(-1);
+ }
+ bb_error_msg("device `%s' has HW address %s `%s'.\n",
+ ifname, xhw->name, xhw->print((char *)&ifr.ifr_hwaddr.sa_data));
+ }
+ return 0;
+}
+
+/* Set an entry in the ARP cache. */
+static int arp_set(char **args)
+{
+ char host[128];
+ struct arpreq req;
+ struct sockaddr sa;
+ int flags;
+
+ memset((char *) &req, 0, sizeof(req));
+
+ /* Resolve the host name. */
+ if (*args == NULL) {
+ bb_error_msg("need host name\n");
+ return -1;
+ }
+ safe_strncpy(host, *args++, (sizeof host));
+ if (ap->input(0, host, &sa) < 0) {
+ bb_herror_msg("%s", host);
+ return -1;
+ }
+ /* If a host has more than one address, use the correct one! */
+ memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
+
+ /* Fetch the hardware address. */
+ if (*args == NULL) {
+ bb_error_msg("need hardware address\n");
+ return -1;
+ }
+ if (opt_D) {
+ if (arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL) < 0)
+ return (-1);
+ } else {
+ if (hw->input(*args++, &req.arp_ha) < 0) {
+ bb_error_msg("invalid hardware address\n");
+ return -1;
+ }
+ }
+
+ /* Check out any modifiers. */
+ flags = ATF_PERM | ATF_COM;
+ while (*args != NULL) {
+ if (!strcmp(*args, "temp")) {
+ flags &= ~ATF_PERM;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "pub")) {
+ flags |= ATF_PUBL;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "priv")) {
+ flags &= ~ATF_PUBL;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "trail")) {
+ flags |= ATF_USETRAILERS;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "dontpub")) {
+#ifdef HAVE_ATF_DONTPUB
+ flags |= ATF_DONTPUB;
+#else
+ bb_error_msg("feature ATF_DONTPUB is not supported");
+#endif
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "auto")) {
+#ifdef HAVE_ATF_MAGIC
+ flags |= ATF_MAGIC;
+#else
+ bb_error_msg("feature ATF_MAGIC is not supported");
+#endif
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "dev")) {
+ if (*++args == NULL)
+ bb_show_usage();
+ safe_strncpy(device, *args, sizeof(device));
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "netmask")) {
+ if (*++args == NULL)
+ bb_show_usage();
+ if (strcmp(*args, "255.255.255.255") != 0) {
+ strcpy(host, *args);
+ if (ap->input(0, host, &sa) < 0) {
+ bb_herror_msg("%s", host);
+ return (-1);
+ }
+ memcpy((char *) &req.arp_netmask, (char *) &sa,
+ sizeof(struct sockaddr));
+ flags |= ATF_NETMASK;
+ }
+ args++;
+ continue;
+ }
+ bb_show_usage();
+ }
+
+ /* Fill in the remainder of the request. */
+ req.arp_flags = flags;
+
+ strcpy(req.arp_dev, device);
+
+ /* Call the kernel. */
+ if (opt_v)
+ bb_error_msg("SIOCSARP()\n");
+ if (ioctl(sockfd, SIOCSARP, &req) < 0) {
+ perror("SIOCSARP");
+ return -1;
+ }
+ return 0;
+}
+
+/* Process an EtherFile */
+static int arp_file(char *name)
+{
+ char buff[1024];
+ char *sp, *args[32];
+ int linenr, argc;
+ FILE *fp;
+
+ if ((fp = fopen(name, "r")) == NULL) {
+ bb_error_msg("cannot open etherfile %s!\n", name);
+ return -1;
+ }
+
+ /* Read the lines in the file. */
+ linenr = 0;
+ while (fgets(buff, sizeof(buff), fp) != (char *) NULL) {
+ linenr++;
+ if (opt_v == 1)
+ fprintf(stderr, ">> %s", buff);
+ if ((sp = strchr(buff, '\n')) != (char *) NULL)
+ *sp = '\0';
+ if (buff[0] == '#' || buff[0] == '\0')
+ continue;
+
+ argc = getargs(buff, args);
+ if (argc < 2) {
+ bb_error_msg("format error on line %u of etherfile %s!\n",
+ linenr, name);
+ continue;
+ }
+ if (strchr (args[0], ':') != NULL) {
+ /* We have a correct ethers file, switch hw adress and hostname
+ for arp */
+ char *cp;
+ cp = args[1];
+ args[1] = args[0];
+ args[0] = cp;
+ }
+ if (arp_set(args) != 0)
+ bb_error_msg("cannot set entry on line %u of etherfile %s!\n",
+ linenr, name);
+ }
+
+ (void) fclose(fp);
+
+ return 0;
+}
+
+/* Print the contents of an ARP request block. */
+static void arp_disp_2(char *name, int type, int arp_flags, char *hwa,
+ char *mask, char *dev)
+{
+ static int title = 0;
+ struct hwtype *xhw;
+ char flags[10];
+
+ xhw = get_hwntype(type);
+ if (xhw == NULL)
+ xhw = get_hwtype(DFLT_HW);
+
+ if (title++ == 0) {
+ printf("Address HWtype HWaddress Flags Mask Iface\n");
+ }
+ /* Setup the flags. */
+ flags[0] = '\0';
+ if (arp_flags & ATF_COM)
+ strcat(flags, "C");
+ if (arp_flags & ATF_PERM)
+ strcat(flags, "M");
+ if (arp_flags & ATF_PUBL)
+ strcat(flags, "P");
+#ifdef HAVE_ATF_MAGIC
+ if (arp_flags & ATF_MAGIC)
+ strcat(flags, "A");
+#endif
+#ifdef HAVE_ATF_DONTPUB
+ if (arp_flags & ATF_DONTPUB)
+ strcat(flags, "!");
+#endif
+ if (arp_flags & ATF_USETRAILERS)
+ strcat(flags, "T");
+
+ if (!(arp_flags & ATF_NETMASK))
+ mask = "";
+
+ printf("%-23.23s ", name);
+
+ if (!(arp_flags & ATF_COM)) {
+ if (arp_flags & ATF_PUBL)
+ printf("%-8.8s%-20.20s", "*", "*");
+ else
+ printf("%-8.8s%-20.20s", "", "(incomplete)");
+ } else {
+ printf("%-8.8s%-20.20s", xhw->name, hwa);
+ }
+
+ printf("%-6.6s%-15.15s %s\n", flags, mask, dev);
+}
+
+/* Print the contents of an ARP request block. */
+static void arp_disp(char *name, char *ip, int type, int arp_flags,
+ char *hwa, char *mask, char *dev)
+{
+ struct hwtype *xhw;
+
+ xhw = get_hwntype(type);
+ if (xhw == NULL)
+ xhw = get_hwtype(DFLT_HW);
+
+ printf("%s (%s) at ", name, ip);
+
+ if (!(arp_flags & ATF_COM)) {
+ if (arp_flags & ATF_PUBL)
+ printf("* ");
+ else
+ printf("<incomplete> ");
+ } else {
+ printf("%s [%s] ", hwa, xhw->name);
+ }
+
+ if (arp_flags & ATF_NETMASK)
+ printf("netmask %s ", mask);
+
+ if (arp_flags & ATF_PERM)
+ printf("PERM ");
+ if (arp_flags & ATF_PUBL)
+ printf("PUP ");
+#ifdef HAVE_ATF_MAGIC
+ if (arp_flags & ATF_MAGIC)
+ printf("AUTO ");
+#endif
+#ifdef HAVE_ATF_DONTPUB
+ if (arp_flags & ATF_DONTPUB)
+ printf("DONTPUB ");
+#endif
+ if (arp_flags & ATF_USETRAILERS)
+ printf("TRAIL ");
+
+ printf("on %s\n", dev);
+}
+
+/* Display the contents of the ARP cache in the kernel. */
+static int arp_show(char *name)
+{
+ char host[100];
+ struct sockaddr sa;
+ char ip[100];
+ char hwa[100];
+ char mask[100];
+ char line[200];
+ char dev[100];
+ int type, flags;
+ FILE *fp;
+ char *hostname;
+ int num, entries = 0, showed = 0;
+
+ host[0] = '\0';
+
+ if (name != NULL) {
+ /* Resolve the host name. */
+ safe_strncpy(host, name, (sizeof host));
+ if (ap->input(0, host, &sa) < 0) {
+ bb_herror_msg("%s", host);
+ return -1;
+ }
+ safe_strncpy(host, ap->sprint(&sa, 1), sizeof(host));
+ }
+ /* Open the PROCps kernel table. */
+ if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL) {
+ perror(_PATH_PROCNET_ARP);
+ return -1;
+ }
+ /* Bypass header -- read until newline */
+ if (fgets(line, sizeof(line), fp) != (char *) NULL) {
+ strcpy(mask, "-");
+ strcpy(dev, "-");
+ /* Read the ARP cache entries. */
+ for (; fgets(line, sizeof(line), fp);) {
+ num = sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n",
+ ip, &type, &flags, hwa, mask, dev);
+ if (num < 4)
+ break;
+
+ entries++;
+ /* if the user specified hw-type differs, skip it */
+ if (hw_set && (type != hw->type))
+ continue;
+
+ /* if the user specified address differs, skip it */
+ if (host[0] && strcmp(ip, host))
+ continue;
+
+ /* if the user specified device differs, skip it */
+ if (device[0] && strcmp(dev, device))
+ continue;
+
+ showed++;
+ /* This IS ugly but it works -be */
+ if (opt_n)
+ hostname = "?";
+ else {
+ if (ap->input(0, ip, &sa) < 0)
+ hostname = ip;
+ else
+ hostname = ap->sprint(&sa, opt_n | 0x8000);
+ if (strcmp(hostname, ip) == 0)
+ hostname = "?";
+ }
+
+ if (opt_e)
+ arp_disp_2(hostname[0] == '?' ? ip : hostname, type, flags,
+ hwa, mask, dev);
+ else
+ arp_disp(hostname, ip, type, flags, hwa, mask, dev);
+ }
+ }
+ if (opt_v)
+ printf("Entries: %d\tSkipped: %d\tFound: %d\n",
+ entries, entries - showed, showed);
+
+ if (!showed) {
+ if (host[0] && !opt_a)
+ printf("%s (%s) -- no entry\n", name, host);
+ else if (hw_set || host[0] || device[0]) {
+ printf("in %d entries no match found.\n", entries);
+ }
+ }
+
+ (void) fclose(fp);
+
+ return 0;
+}
+
+int arp_main(int argc, char **argv)
+{
+ int what, i;
+
+ /* Initialize variables... */
+ if ((hw = get_hwtype(DFLT_HW)) == NULL) {
+ bb_error_msg("%s: hardware type not supported!\n", DFLT_HW);
+ return -1;
+ }
+ if ((ap = get_aftype(DFLT_AF)) == NULL) {
+ bb_error_msg("%s: address family not supported!\n", DFLT_AF);
+ return -1;
+ }
+ what = 0;
+
+ /* Fetch the command-line arguments. */
+ while ((i = getopt(argc, argv, "A:H:adfp:nsei:t:vh?DNV")) != EOF)
+ switch (i) {
+ case 'a':
+ what = 1;
+ opt_a = 1;
+ break;
+ case 'f':
+ what = 2;
+ break;
+ case 'd':
+ what = 3;
+ break;
+ case 's':
+ what = 4;
+ break;
+ case 'e':
+ opt_e = 1;
+ break;
+ case 'n':
+ opt_n = 1;
+ break;
+ case 'D':
+ opt_D = 1;
+ break;
+ case 'v':
+ opt_v = 1;
+ break;
+ case 'A':
+ case 'p':
+ ap = get_aftype(optarg);
+ if (ap == NULL) {
+ bb_error_msg("%s: unknown address family.\n", optarg);
+ exit(-1);
+ }
+ break;
+ case 'H':
+ case 't':
+ hw = get_hwtype(optarg);
+ if (hw == NULL) {
+ bb_error_msg("%s: unknown hardware type.\n", optarg);
+ exit(-1);
+ }
+ hw_set = 1;
+ break;
+ case 'i':
+ safe_strncpy(device, optarg, sizeof(device));
+ break;
+ case '?':
+ case 'h':
+ default:
+ bb_show_usage();
+ }
+
+ if (ap->af != AF_INET) {
+ bb_error_msg("%s: kernel only supports 'inet'.\n", ap->name);
+ exit(-1);
+ }
+
+ /* If not hw type specified get default */
+ if (hw_set==0) {
+ if ((hw = get_hwtype(DFLT_HW)) == NULL) {
+ bb_error_msg("%s: hardware type not supported!\n", DFLT_HW);
+ return (-1);
+ }
+ }
+
+ if (hw->alen <= 0) {
+ bb_error_msg("%s: hardware type without ARP support.\n", hw->name);
+ exit(-1);
+ }
+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return -1;
+ }
+ /* Now see what we have to do here... */
+ switch (what) {
+ case 0:
+ opt_e = 1;
+ what = arp_show(argv[optind]);
+ break;
+
+ case 1: /* show an ARP entry in the cache */
+ what = arp_show(argv[optind]);
+ break;
+
+ case 2: /* process an EtherFile */
+ what = arp_file(argv[optind] ? argv[optind] : "/etc/ethers");
+ break;
+
+ case 3: /* delete an ARP entry from the cache */
+ what = arp_del(&argv[optind]);
+ break;
+
+ case 4: /* set an ARP entry in the cache */
+ what = arp_set(&argv[optind]);
+ break;
+
+ default:
+ bb_show_usage();
+ }
+
+ return what;
+}
+
diff -ruN busybox-1.00-pre10/networking/Config.in busybox-1.00-pre10+arp/networking/Config.in
--- busybox-1.00-pre10/networking/Config.in 2004-03-15 03:28:48.000000000 -0500
+++ busybox-1.00-pre10+arp/networking/Config.in 2004-04-26 12:24:12.000000000 -0400
@@ -12,6 +12,12 @@
Enable IPv6 support to busybox. This makes applets that talk IP
able to work with IPv6.
+config CONFIG_ARP
+ bool "arp"
+ default n
+ help
+ Manipulate the system ARP cache
+
config CONFIG_ARPING
bool "arping"
default n
diff -ruN busybox-1.00-pre10/networking/Makefile.in busybox-1.00-pre10+arp/networking/Makefile.in
--- busybox-1.00-pre10/networking/Makefile.in 2004-04-06 12:56:00.000000000 -0400
+++ busybox-1.00-pre10+arp/networking/Makefile.in 2004-04-26 12:18:13.000000000 -0400
@@ -23,6 +23,7 @@
endif
NETWORKING-y:=
+NETWORKING-$(CONFIG_ARP) += arp.o
NETWORKING-$(CONFIG_ARPING) += arping.o
NETWORKING-$(CONFIG_FTPGET) += ftpgetput.o
NETWORKING-$(CONFIG_FTPPUT) += ftpgetput.o
More information about the busybox
mailing list