|  | /* vi: set sw=4 ts=4: */ | 
|  | /* | 
|  | * Mini ipcalc implementation for busybox | 
|  | * | 
|  | * By Jordan Crouse <jordan@cosmicpenguin.net> | 
|  | *    Stephan Linz  <linz@li-pro.net> | 
|  | * | 
|  | * This is a complete reimplementation of the ipcalc program | 
|  | * from Red Hat.  I didn't look at their source code, but there | 
|  | * is no denying that this is a loving reimplementation | 
|  | * | 
|  | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 
|  | */ | 
|  |  | 
|  | //usage:#define ipcalc_trivial_usage | 
|  | //usage:       "[OPTIONS] ADDRESS[[/]NETMASK] [NETMASK]" | 
|  | //usage:#define ipcalc_full_usage "\n\n" | 
|  | //usage:       "Calculate IP network settings from a IP address\n" | 
|  | //usage:	IF_FEATURE_IPCALC_LONG_OPTIONS( | 
|  | //usage:     "\n	-b,--broadcast	Display calculated broadcast address" | 
|  | //usage:     "\n	-n,--network	Display calculated network address" | 
|  | //usage:     "\n	-m,--netmask	Display default netmask for IP" | 
|  | //usage:	IF_FEATURE_IPCALC_FANCY( | 
|  | //usage:     "\n	-p,--prefix	Display the prefix for IP/NETMASK" | 
|  | //usage:     "\n	-h,--hostname	Display first resolved host name" | 
|  | //usage:     "\n	-s,--silent	Don't ever display error messages" | 
|  | //usage:	) | 
|  | //usage:	) | 
|  | //usage:	IF_NOT_FEATURE_IPCALC_LONG_OPTIONS( | 
|  | //usage:     "\n	-b	Display calculated broadcast address" | 
|  | //usage:     "\n	-n	Display calculated network address" | 
|  | //usage:     "\n	-m	Display default netmask for IP" | 
|  | //usage:	IF_FEATURE_IPCALC_FANCY( | 
|  | //usage:     "\n	-p	Display the prefix for IP/NETMASK" | 
|  | //usage:     "\n	-h	Display first resolved host name" | 
|  | //usage:     "\n	-s	Don't ever display error messages" | 
|  | //usage:	) | 
|  | //usage:	) | 
|  |  | 
|  | #include "libbb.h" | 
|  | /* After libbb.h, because on some systems it needs other includes */ | 
|  | #include <arpa/inet.h> | 
|  |  | 
|  | #define CLASS_A_NETMASK ntohl(0xFF000000) | 
|  | #define CLASS_B_NETMASK ntohl(0xFFFF0000) | 
|  | #define CLASS_C_NETMASK ntohl(0xFFFFFF00) | 
|  |  | 
|  | static unsigned long get_netmask(unsigned long ipaddr) | 
|  | { | 
|  | ipaddr = htonl(ipaddr); | 
|  |  | 
|  | if ((ipaddr & 0xC0000000) == 0xC0000000) | 
|  | return CLASS_C_NETMASK; | 
|  | else if ((ipaddr & 0x80000000) == 0x80000000) | 
|  | return CLASS_B_NETMASK; | 
|  | else if ((ipaddr & 0x80000000) == 0) | 
|  | return CLASS_A_NETMASK; | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #if ENABLE_FEATURE_IPCALC_FANCY | 
|  | static int get_prefix(unsigned long netmask) | 
|  | { | 
|  | unsigned long msk = 0x80000000; | 
|  | int ret = 0; | 
|  |  | 
|  | netmask = htonl(netmask); | 
|  | while (msk) { | 
|  | if (netmask & msk) | 
|  | ret++; | 
|  | msk >>= 1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  | #else | 
|  | int get_prefix(unsigned long netmask); | 
|  | #endif | 
|  |  | 
|  |  | 
|  | #define NETMASK   0x01 | 
|  | #define BROADCAST 0x02 | 
|  | #define NETWORK   0x04 | 
|  | #define NETPREFIX 0x08 | 
|  | #define HOSTNAME  0x10 | 
|  | #define SILENT    0x20 | 
|  |  | 
|  | #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS | 
|  | static const char ipcalc_longopts[] ALIGN1 = | 
|  | "netmask\0"   No_argument "m" // netmask from IP (assuming complete class A, B, or C network) | 
|  | "broadcast\0" No_argument "b" // broadcast from IP [netmask] | 
|  | "network\0"   No_argument "n" // network from IP [netmask] | 
|  | # if ENABLE_FEATURE_IPCALC_FANCY | 
|  | "prefix\0"    No_argument "p" // prefix from IP[/prefix] [netmask] | 
|  | "hostname\0"  No_argument "h" // hostname from IP | 
|  | "silent\0"    No_argument "s" // don’t ever display error messages | 
|  | # endif | 
|  | ; | 
|  | #endif | 
|  |  | 
|  | int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 
|  | int ipcalc_main(int argc UNUSED_PARAM, char **argv) | 
|  | { | 
|  | unsigned opt; | 
|  | bool have_netmask = 0; | 
|  | struct in_addr s_netmask, s_broadcast, s_network, s_ipaddr; | 
|  | /* struct in_addr { in_addr_t s_addr; }  and  in_addr_t | 
|  | * (which in turn is just a typedef to uint32_t) | 
|  | * are essentially the same type. A few macros for less verbosity: */ | 
|  | #define netmask   (s_netmask.s_addr) | 
|  | #define broadcast (s_broadcast.s_addr) | 
|  | #define network   (s_network.s_addr) | 
|  | #define ipaddr    (s_ipaddr.s_addr) | 
|  | char *ipstr; | 
|  |  | 
|  | #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS | 
|  | applet_long_options = ipcalc_longopts; | 
|  | #endif | 
|  | opt_complementary = "-1:?2"; /* minimum 1 arg, maximum 2 args */ | 
|  | opt = getopt32(argv, "mbn" IF_FEATURE_IPCALC_FANCY("phs")); | 
|  | argv += optind; | 
|  | if (opt & SILENT) | 
|  | logmode = LOGMODE_NONE; /* suppress error_msg() output */ | 
|  | opt &= ~SILENT; | 
|  | if (!(opt & (BROADCAST | NETWORK | NETPREFIX))) { | 
|  | /* if no options at all or | 
|  | * (no broadcast,network,prefix) and (two args)... */ | 
|  | if (!opt || argv[1]) | 
|  | bb_show_usage(); | 
|  | } | 
|  |  | 
|  | ipstr = argv[0]; | 
|  | if (ENABLE_FEATURE_IPCALC_FANCY) { | 
|  | unsigned long netprefix = 0; | 
|  | char *prefixstr; | 
|  |  | 
|  | prefixstr = ipstr; | 
|  |  | 
|  | while (*prefixstr) { | 
|  | if (*prefixstr == '/') { | 
|  | *prefixstr++ = '\0'; | 
|  | if (*prefixstr) { | 
|  | unsigned msk; | 
|  | netprefix = xatoul_range(prefixstr, 0, 32); | 
|  | netmask = 0; | 
|  | msk = 0x80000000; | 
|  | while (netprefix > 0) { | 
|  | netmask |= msk; | 
|  | msk >>= 1; | 
|  | netprefix--; | 
|  | } | 
|  | netmask = htonl(netmask); | 
|  | /* Even if it was 0, we will signify that we have a netmask. This allows */ | 
|  | /* for specification of default routes, etc which have a 0 netmask/prefix */ | 
|  | have_netmask = 1; | 
|  | } | 
|  | break; | 
|  | } | 
|  | prefixstr++; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (inet_aton(ipstr, &s_ipaddr) == 0) { | 
|  | bb_error_msg_and_die("bad IP address: %s", argv[0]); | 
|  | } | 
|  |  | 
|  | if (argv[1]) { | 
|  | if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) { | 
|  | bb_error_msg_and_die("use prefix or netmask, not both"); | 
|  | } | 
|  | if (inet_aton(argv[1], &s_netmask) == 0) { | 
|  | bb_error_msg_and_die("bad netmask: %s", argv[1]); | 
|  | } | 
|  | } else { | 
|  | /* JHC - If the netmask wasn't provided then calculate it */ | 
|  | if (!ENABLE_FEATURE_IPCALC_FANCY || !have_netmask) | 
|  | netmask = get_netmask(ipaddr); | 
|  | } | 
|  |  | 
|  | if (opt & NETMASK) { | 
|  | printf("NETMASK=%s\n", inet_ntoa(s_netmask)); | 
|  | } | 
|  |  | 
|  | if (opt & BROADCAST) { | 
|  | broadcast = (ipaddr & netmask) | ~netmask; | 
|  | printf("BROADCAST=%s\n", inet_ntoa(s_broadcast)); | 
|  | } | 
|  |  | 
|  | if (opt & NETWORK) { | 
|  | network = ipaddr & netmask; | 
|  | printf("NETWORK=%s\n", inet_ntoa(s_network)); | 
|  | } | 
|  |  | 
|  | if (ENABLE_FEATURE_IPCALC_FANCY) { | 
|  | if (opt & NETPREFIX) { | 
|  | printf("PREFIX=%i\n", get_prefix(netmask)); | 
|  | } | 
|  |  | 
|  | if (opt & HOSTNAME) { | 
|  | struct hostent *hostinfo; | 
|  |  | 
|  | hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET); | 
|  | if (!hostinfo) { | 
|  | bb_herror_msg_and_die("can't find hostname for %s", argv[0]); | 
|  | } | 
|  | str_tolower(hostinfo->h_name); | 
|  |  | 
|  | printf("HOSTNAME=%s\n", hostinfo->h_name); | 
|  | } | 
|  | } | 
|  |  | 
|  | return EXIT_SUCCESS; | 
|  | } |