busybox/networking/ipcalc.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Mini ipcalc implementation for busybox
   4 *
   5 * By Jordan Crouse <jordan@cosmicpenguin.net>
   6 *    Stephan Linz  <linz@li-pro.net>
   7 *
   8 * This is a complete reimplementation of the ipcalc program
   9 * from Red Hat.  I didn't look at their source code, but there
  10 * is no denying that this is a loving reimplementation
  11 *
  12 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  13 */
  14//config:config IPCALC
  15//config:       bool "ipcalc (4.4 kb)"
  16//config:       default y
  17//config:       help
  18//config:       ipcalc takes an IP address and netmask and calculates the
  19//config:       resulting broadcast, network, and host range.
  20//config:
  21//config:config FEATURE_IPCALC_LONG_OPTIONS
  22//config:       bool "Enable long options"
  23//config:       default y
  24//config:       depends on IPCALC && LONG_OPTS
  25//config:
  26//config:config FEATURE_IPCALC_FANCY
  27//config:       bool "Fancy IPCALC, more options, adds 1 kbyte"
  28//config:       default y
  29//config:       depends on IPCALC
  30//config:       help
  31//config:       Adds the options hostname, prefix and silent to the output of
  32//config:       "ipcalc".
  33
  34//applet:IF_IPCALC(APPLET_NOEXEC(ipcalc, ipcalc, BB_DIR_BIN, BB_SUID_DROP, ipcalc))
  35
  36//kbuild:lib-$(CONFIG_IPCALC) += ipcalc.o
  37
  38//usage:#define ipcalc_trivial_usage
  39//usage:       "[OPTIONS] ADDRESS"
  40//usage:       IF_FEATURE_IPCALC_FANCY("[/PREFIX]") " [NETMASK]"
  41//usage:#define ipcalc_full_usage "\n\n"
  42//usage:       "Calculate and display network settings from IP address\n"
  43//usage:     "\n        -b      Broadcast address"
  44//usage:     "\n        -n      Network address"
  45//usage:     "\n        -m      Default netmask for IP"
  46//usage:        IF_FEATURE_IPCALC_FANCY(
  47//usage:     "\n        -p      Prefix for IP/NETMASK"
  48//usage:     "\n        -h      Resolved host name"
  49//usage:     "\n        -s      No error messages"
  50//usage:        )
  51
  52#include "libbb.h"
  53/* After libbb.h, because on some systems it needs other includes */
  54#include <arpa/inet.h>
  55
  56#define CLASS_A_NETMASK ntohl(0xFF000000)
  57#define CLASS_B_NETMASK ntohl(0xFFFF0000)
  58#define CLASS_C_NETMASK ntohl(0xFFFFFF00)
  59
  60static unsigned long get_netmask(unsigned long ipaddr)
  61{
  62        ipaddr = htonl(ipaddr);
  63
  64        if ((ipaddr & 0xC0000000) == 0xC0000000)
  65                return CLASS_C_NETMASK;
  66        else if ((ipaddr & 0x80000000) == 0x80000000)
  67                return CLASS_B_NETMASK;
  68        else if ((ipaddr & 0x80000000) == 0)
  69                return CLASS_A_NETMASK;
  70        else
  71                return 0;
  72}
  73
  74#if ENABLE_FEATURE_IPCALC_FANCY
  75static int get_prefix(unsigned long netmask)
  76{
  77        unsigned long msk = 0x80000000;
  78        int ret = 0;
  79
  80        netmask = htonl(netmask);
  81        while (msk) {
  82                if (netmask & msk)
  83                        ret++;
  84                msk >>= 1;
  85        }
  86        return ret;
  87}
  88#else
  89int get_prefix(unsigned long netmask);
  90#endif
  91
  92
  93#define NETMASK   0x01
  94#define BROADCAST 0x02
  95#define NETWORK   0x04
  96#define NETPREFIX 0x08
  97#define HOSTNAME  0x10
  98#define SILENT    0x20
  99
 100#if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
 101        static const char ipcalc_longopts[] ALIGN1 =
 102                "netmask\0"   No_argument "m" // netmask from IP (assuming complete class A, B, or C network)
 103                "broadcast\0" No_argument "b" // broadcast from IP [netmask]
 104                "network\0"   No_argument "n" // network from IP [netmask]
 105# if ENABLE_FEATURE_IPCALC_FANCY
 106                "prefix\0"    No_argument "p" // prefix from IP[/prefix] [netmask]
 107                "hostname\0"  No_argument "h" // hostname from IP
 108                "silent\0"    No_argument "s" // don’t ever display error messages
 109# endif
 110                ;
 111# define GETOPT32 getopt32long
 112# define LONGOPTS ,ipcalc_longopts
 113#else
 114# define GETOPT32 getopt32
 115# define LONGOPTS
 116#endif
 117
 118int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 119int ipcalc_main(int argc UNUSED_PARAM, char **argv)
 120{
 121        unsigned opt;
 122        bool have_netmask = 0;
 123        struct in_addr s_netmask, s_broadcast, s_network, s_ipaddr;
 124        /* struct in_addr { in_addr_t s_addr; }  and  in_addr_t
 125         * (which in turn is just a typedef to uint32_t)
 126         * are essentially the same type. A few macros for less verbosity: */
 127#define netmask   (s_netmask.s_addr)
 128#define broadcast (s_broadcast.s_addr)
 129#define network   (s_network.s_addr)
 130#define ipaddr    (s_ipaddr.s_addr)
 131        char *ipstr;
 132
 133        opt = GETOPT32(argv, "^"
 134                        "mbn" IF_FEATURE_IPCALC_FANCY("phs")
 135                        "\0" "-1:?2"/*min 1, max 2 args*/
 136                        LONGOPTS
 137        );
 138        argv += optind;
 139        if (opt & SILENT)
 140                logmode = LOGMODE_NONE; /* suppress error_msg() output */
 141        opt &= ~SILENT;
 142        if (!(opt & (BROADCAST | NETWORK | NETPREFIX))) {
 143                /* if no options at all or
 144                 * (no broadcast,network,prefix) and (two args)... */
 145                if (!opt || argv[1])
 146                        bb_show_usage();
 147        }
 148
 149        ipstr = argv[0];
 150        if (ENABLE_FEATURE_IPCALC_FANCY) {
 151                unsigned long netprefix = 0;
 152                char *prefixstr;
 153
 154                prefixstr = ipstr;
 155
 156                while (*prefixstr) {
 157                        if (*prefixstr == '/') {
 158                                *prefixstr++ = '\0';
 159                                if (*prefixstr) {
 160                                        unsigned msk;
 161                                        netprefix = xatoul_range(prefixstr, 0, 32);
 162                                        netmask = 0;
 163                                        msk = 0x80000000;
 164                                        while (netprefix > 0) {
 165                                                netmask |= msk;
 166                                                msk >>= 1;
 167                                                netprefix--;
 168                                        }
 169                                        netmask = htonl(netmask);
 170                                        /* Even if it was 0, we will signify that we have a netmask. This allows */
 171                                        /* for specification of default routes, etc which have a 0 netmask/prefix */
 172                                        have_netmask = 1;
 173                                }
 174                                break;
 175                        }
 176                        prefixstr++;
 177                }
 178        }
 179
 180        if (inet_aton(ipstr, &s_ipaddr) == 0) {
 181                bb_error_msg_and_die("bad IP address: %s", argv[0]);
 182        }
 183
 184        if (argv[1]) {
 185                if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) {
 186                        bb_error_msg_and_die("use prefix or netmask, not both");
 187                }
 188                if (inet_aton(argv[1], &s_netmask) == 0) {
 189                        bb_error_msg_and_die("bad netmask: %s", argv[1]);
 190                }
 191        } else {
 192                /* JHC - If the netmask wasn't provided then calculate it */
 193                if (!ENABLE_FEATURE_IPCALC_FANCY || !have_netmask)
 194                        netmask = get_netmask(ipaddr);
 195        }
 196
 197        if (opt & NETMASK) {
 198                printf("NETMASK=%s\n", inet_ntoa(s_netmask));
 199        }
 200
 201        if (opt & BROADCAST) {
 202                broadcast = (ipaddr & netmask) | ~netmask;
 203                printf("BROADCAST=%s\n", inet_ntoa(s_broadcast));
 204        }
 205
 206        if (opt & NETWORK) {
 207                network = ipaddr & netmask;
 208                printf("NETWORK=%s\n", inet_ntoa(s_network));
 209        }
 210
 211        if (ENABLE_FEATURE_IPCALC_FANCY) {
 212                if (opt & NETPREFIX) {
 213                        printf("PREFIX=%i\n", get_prefix(netmask));
 214                }
 215
 216                if (opt & HOSTNAME) {
 217                        struct hostent *hostinfo;
 218
 219                        hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET);
 220                        if (!hostinfo) {
 221                                bb_herror_msg_and_die("can't find hostname for %s", argv[0]);
 222                        }
 223                        str_tolower(hostinfo->h_name);
 224
 225                        printf("HOSTNAME=%s\n", hostinfo->h_name);
 226                }
 227        }
 228
 229        return EXIT_SUCCESS;
 230}
 231