From fa85b86f388fb037b67fa7fcc3b5502c8d0fa84a Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sun, 7 Jan 2007 01:24:12 +0000 Subject: [PATCH] add arp applet - thanks to "Eric Spakman" --- include/applets.h | 1 + include/libbb.h | 37 +++++++++ include/usage.h | 20 +++++ networking/Config.in | 6 ++ networking/Kbuild | 1 + networking/interface.c | 200 ++++++++++++++++++++++++++++++++++++++++--------- 6 files changed, 230 insertions(+), 35 deletions(-) diff --git a/include/applets.h b/include/applets.h index 8586ffc..465ecdb 100644 --- a/include/applets.h +++ b/include/applets.h @@ -56,6 +56,7 @@ USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_AR(APPLET(ar, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) +USE_ARP(APPLET(arp, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_ARPING(APPLET(arping, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_ASH(APPLET_NOUSAGE(ash, ash, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_AWK(APPLET(awk, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) diff --git a/include/libbb.h b/include/libbb.h index e92e4db..6f66c85 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -121,6 +121,38 @@ /* scary. better ideas? (but do *test* them first!) */ #define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1))) +/* 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; +}; + /* Some useful definitions */ #undef FALSE #define FALSE ((int) 0) @@ -426,8 +458,13 @@ extern int bb_test(int argc, char** argv); int create_icmp_socket(void); int create_icmp6_socket(void); /* interface.c */ +struct aftype; +struct hwtype; extern int interface_opt_a; int display_interfaces(char *ifname); +struct aftype *get_aftype(const char *name); +const struct hwtype *get_hwtype(const char *name); +const struct hwtype *get_hwntype(int type); #ifndef BUILD_INDIVIDUAL diff --git a/include/usage.h b/include/usage.h index ae03d54..cfae4e1 100644 --- a/include/usage.h +++ b/include/usage.h @@ -55,6 +55,26 @@ " -x Extract\n" \ " -v Verbosely list files processed" +#define arp_trivial_usage \ + "\n" \ + "[-vn] [-H type] [-i if] -a [hostname]\n" \ + "[-v] [-i if] -d hostname [pub]\n" \ + "[-v] [-H type] [-i if] -s hostname hw_addr [temp]\n" \ + "[-v] [-H type] [-i if] -s hostname hw_addr [netmask nm] pub\n" \ + "[-v] [-H type] [-i if] -Ds hostname ifa [netmask nm] pub\n" +#define arp_full_usage \ + "Manipulate the system ARP cache" \ + "\n\nOptions:" \ + "\n -a Display (all) hosts" \ + "\n -s Set a new ARP entry" \ + "\n -d Delete a specified entry" \ + "\n -v Verbose" \ + "\n -n Don't resolve names" \ + "\n -i if Specify network interface (e.g. eth0)" \ + "\n -D Read from given device" \ + "\n -A, -p Specify protocol family" \ + "\n -H hwtype Specify hardware address type" + #define arping_trivial_usage \ "[-fqbDUA] [-c count] [-w timeout] [-i device] [-s sender] target" #define arping_full_usage \ diff --git a/networking/Config.in b/networking/Config.in index b2d973f..88ccb16 100644 --- a/networking/Config.in +++ b/networking/Config.in @@ -12,6 +12,12 @@ config FEATURE_IPV6 Enable IPv6 support in busybox. This adds IPv6 support in the networking applets. +config ARP + bool "arp" + default n + help + Manipulate the system ARP cache + config ARPING bool "arping" default n diff --git a/networking/Kbuild b/networking/Kbuild index a9a51fc..4c29e45 100644 --- a/networking/Kbuild +++ b/networking/Kbuild @@ -5,6 +5,7 @@ # Licensed under the GPL v2, see the file LICENSE in this tarball. lib-y:= +lib-$(CONFIG_ARP) += arp.o interface.o lib-$(CONFIG_ARPING) += arping.o lib-$(CONFIG_DNSD) += dnsd.o lib-$(CONFIG_ETHER_WAKE) += ether-wake.o diff --git a/networking/interface.c b/networking/interface.c index b39298c..6d23e9b 100644 --- a/networking/interface.c +++ b/networking/interface.c @@ -91,26 +91,6 @@ struct in6_ifreq { #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; -}; - /* Display an Internet socket address. */ static char *INET_sprint(struct sockaddr *sap, int numeric) { @@ -126,12 +106,66 @@ static char *INET_sprint(struct sockaddr *sap, int numeric) return buff; } +static int INET_getsock(char *bufp, struct sockaddr *sap) +{ + char *sp = bufp, *bp; + unsigned int i; + unsigned val; + struct sockaddr_in *sock_in; + + 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 ((unsigned)(*sp - 'A') <= 5) + bp[i] |= (int) (*sp - ('A' - 10)); + else if (isdigit(*sp)) + bp[i] |= (int) (*sp - '0'); + else + return -1; + + bp[i] <<= 4; + sp++; + *sp = toupper(*sp); + + if ((unsigned)(*sp - 'A') <= 5) + bp[i] |= (int) (*sp - ('A' - 10)); + else if (isdigit(*sp)) + bp[i] |= (int) (*sp - '0'); + else + return -1; + + sp++; + } + sock_in->sin_addr.s_addr = htonl(val); + + return (sp - bufp); +} + +static int INET_input(int type, char *bufp, struct sockaddr *sap) +{ + switch (type) { + case 1: + return (INET_getsock(bufp, sap)); + case 256: + return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1)); + default: + return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0)); + } +} + static struct aftype inet_aftype = { .name = "inet", .title = "DARPA Internet", .af = AF_INET, .alen = 4, .sprint = INET_sprint, + .input = INET_input, .fd = -1 }; @@ -151,12 +185,37 @@ static char *INET6_sprint(struct sockaddr *sap, int numeric) return buff; } +static int INET6_getsock(char *bufp, struct sockaddr *sap) +{ + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) sap; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + + if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0) + return -1; + + return 16; /* ?;) */ +} + +static int INET6_input(int type, char *bufp, struct sockaddr *sap) +{ + switch (type) { + case 1: + return (INET6_getsock(bufp, sap)); + default: + return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap)); + } +} + static struct aftype inet6_aftype = { .name = "inet6", .title = "IPv6", .af = AF_INET6, .alen = sizeof(struct in6_addr), .sprint = INET6_sprint, + .input = INET6_input, .fd = -1 }; @@ -206,6 +265,20 @@ static struct aftype * const aftypes[] = { }; /* Check our protocol family table for this family. */ +struct aftype *get_aftype(const char *name) +{ + struct aftype * const *afp; + + afp = aftypes; + while (*afp != NULL) { + if (!strcmp((*afp)->name, name)) + return (*afp); + afp++; + } + return NULL; +} + +/* Check our protocol family table for this family. */ static struct aftype *get_afntype(int af) { struct aftype * const *afp; @@ -714,18 +787,6 @@ static int do_if_fetch(struct interface *ife) return 0; } -/* This structure defines hardware protocols and their handlers. */ -struct hwtype { - const char * const 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 const struct hwtype unspec_hwtype = { .name = "unspec", .title = "UNSPEC", @@ -759,14 +820,69 @@ static char *pr_ether(unsigned char *ptr) return buff; } -static const struct hwtype ether_hwtype = { +static int in_ether(char *bufp, struct sockaddr *sap); + +static struct hwtype ether_hwtype = { .name = "ether", .title = "Ethernet", .type = ARPHRD_ETHER, .alen = ETH_ALEN, - .print = pr_ether + .print = pr_ether, + .input = in_ether }; +static unsigned hexchar2int(char c) +{ + if (isdigit(c)) + return c - '0'; + c &= ~0x20; /* a -> A */ + if ((unsigned)(c - 'A') <= 5) + return c - ('A' - 10); + return ~0U; +} + +/* Input an Ethernet address and convert to binary. */ +static int in_ether(char *bufp, struct sockaddr *sap) +{ + unsigned char *ptr; + char c, *orig; + int i; + unsigned val; + + sap->sa_family = ether_hwtype.type; + ptr = sap->sa_data; + + i = 0; + orig = bufp; + while ((*bufp != '\0') && (i < ETH_ALEN)) { + val = hexchar2int(*bufp++) * 0x10; + if (val > 0xff) { + errno = EINVAL; + return -1; + } + c = *bufp; + if (c == ':' || c == 0) + val >>= 4; + else { + val |= hexchar2int(c); + if (val > 0xff) { + errno = EINVAL; + return -1; + } + } + if (c != 0) + bufp++; + *ptr++ = (unsigned char) val; + i++; + + /* We might get a semicolon here - not required. */ + if (*bufp == ':') { + bufp++; + } + } + return 0; +} + #include static const struct hwtype ppp_hwtype = { @@ -811,7 +927,21 @@ static const char * const if_port_text[] = { #endif /* Check our hardware type table for this type. */ -static const struct hwtype *get_hwntype(int type) +const struct hwtype *get_hwtype(const char *name) +{ + const struct hwtype * const *hwp; + + hwp = hwtypes; + while (*hwp != NULL) { + if (!strcmp((*hwp)->name, name)) + return (*hwp); + hwp++; + } + return NULL; +} + +/* Check our hardware type table for this type. */ +const struct hwtype *get_hwntype(int type) { const struct hwtype * const *hwp; -- 2.7.4