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#include "libbb.h"
  15/* After libbb.h, because on some systems it needs other includes */
  16#include <arpa/inet.h>
  17
  18#define CLASS_A_NETMASK ntohl(0xFF000000)
  19#define CLASS_B_NETMASK ntohl(0xFFFF0000)
  20#define CLASS_C_NETMASK ntohl(0xFFFFFF00)
  21
  22static unsigned long get_netmask(unsigned long ipaddr)
  23{
  24        ipaddr = htonl(ipaddr);
  25
  26        if ((ipaddr & 0xC0000000) == 0xC0000000)
  27                return CLASS_C_NETMASK;
  28        else if ((ipaddr & 0x80000000) == 0x80000000)
  29                return CLASS_B_NETMASK;
  30        else if ((ipaddr & 0x80000000) == 0)
  31                return CLASS_A_NETMASK;
  32        else
  33                return 0;
  34}
  35
  36#if ENABLE_FEATURE_IPCALC_FANCY
  37static int get_prefix(unsigned long netmask)
  38{
  39        unsigned long msk = 0x80000000;
  40        int ret = 0;
  41
  42        netmask = htonl(netmask);
  43        while (msk) {
  44                if (netmask & msk)
  45                        ret++;
  46                msk >>= 1;
  47        }
  48        return ret;
  49}
  50#else
  51int get_prefix(unsigned long netmask);
  52#endif
  53
  54
  55#define NETMASK   0x01
  56#define BROADCAST 0x02
  57#define NETWORK   0x04
  58#define NETPREFIX 0x08
  59#define HOSTNAME  0x10
  60#define SILENT    0x20
  61
  62#if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
  63        static const char ipcalc_longopts[] ALIGN1 =
  64                "netmask\0"   No_argument "m" // netmask from IP (assuming complete class A, B, or C network)
  65                "broadcast\0" No_argument "b" // broadcast from IP [netmask]
  66                "network\0"   No_argument "n" // network from IP [netmask]
  67# if ENABLE_FEATURE_IPCALC_FANCY
  68                "prefix\0"    No_argument "p" // prefix from IP[/prefix] [netmask]
  69                "hostname\0"  No_argument "h" // hostname from IP
  70                "silent\0"    No_argument "s" // don’t ever display error messages
  71# endif
  72                ;
  73#endif
  74
  75int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  76int ipcalc_main(int argc UNUSED_PARAM, char **argv)
  77{
  78        unsigned opt;
  79        bool have_netmask = 0;
  80        struct in_addr s_netmask, s_broadcast, s_network, s_ipaddr;
  81        /* struct in_addr { in_addr_t s_addr; }  and  in_addr_t
  82         * (which in turn is just a typedef to uint32_t)
  83         * are essentially the same type. A few macros for less verbosity: */
  84#define netmask   (s_netmask.s_addr)
  85#define broadcast (s_broadcast.s_addr)
  86#define network   (s_network.s_addr)
  87#define ipaddr    (s_ipaddr.s_addr)
  88        char *ipstr;
  89
  90#if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
  91        applet_long_options = ipcalc_longopts;
  92#endif
  93        opt_complementary = "-1:?2"; /* minimum 1 arg, maximum 2 args */
  94        opt = getopt32(argv, "mbn" IF_FEATURE_IPCALC_FANCY("phs"));
  95        argv += optind;
  96        if (opt & SILENT)
  97                logmode = LOGMODE_NONE; /* suppress error_msg() output */
  98        opt &= ~SILENT;
  99        if (!(opt & (BROADCAST | NETWORK | NETPREFIX))) {
 100                /* if no options at all or
 101                 * (no broadcast,network,prefix) and (two args)... */
 102                if (!opt || argv[1])
 103                        bb_show_usage();
 104        }
 105
 106        ipstr = argv[0];
 107        if (ENABLE_FEATURE_IPCALC_FANCY) {
 108                unsigned long netprefix = 0;
 109                char *prefixstr;
 110
 111                prefixstr = ipstr;
 112
 113                while (*prefixstr) {
 114                        if (*prefixstr == '/') {
 115                                *prefixstr++ = '\0';
 116                                if (*prefixstr) {
 117                                        unsigned msk;
 118                                        netprefix = xatoul_range(prefixstr, 0, 32);
 119                                        netmask = 0;
 120                                        msk = 0x80000000;
 121                                        while (netprefix > 0) {
 122                                                netmask |= msk;
 123                                                msk >>= 1;
 124                                                netprefix--;
 125                                        }
 126                                        netmask = htonl(netmask);
 127                                        /* Even if it was 0, we will signify that we have a netmask. This allows */
 128                                        /* for specification of default routes, etc which have a 0 netmask/prefix */
 129                                        have_netmask = 1;
 130                                }
 131                                break;
 132                        }
 133                        prefixstr++;
 134                }
 135        }
 136
 137        if (inet_aton(ipstr, &s_ipaddr) == 0) {
 138                bb_error_msg_and_die("bad IP address: %s", argv[0]);
 139        }
 140
 141        if (argv[1]) {
 142                if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) {
 143                        bb_error_msg_and_die("use prefix or netmask, not both");
 144                }
 145                if (inet_aton(argv[1], &s_netmask) == 0) {
 146                        bb_error_msg_and_die("bad netmask: %s", argv[1]);
 147                }
 148        } else {
 149                /* JHC - If the netmask wasn't provided then calculate it */
 150                if (!ENABLE_FEATURE_IPCALC_FANCY || !have_netmask)
 151                        netmask = get_netmask(ipaddr);
 152        }
 153
 154        if (opt & NETMASK) {
 155                printf("NETMASK=%s\n", inet_ntoa(s_netmask));
 156        }
 157
 158        if (opt & BROADCAST) {
 159                broadcast = (ipaddr & netmask) | ~netmask;
 160                printf("BROADCAST=%s\n", inet_ntoa(s_broadcast));
 161        }
 162
 163        if (opt & NETWORK) {
 164                network = ipaddr & netmask;
 165                printf("NETWORK=%s\n", inet_ntoa(s_network));
 166        }
 167
 168        if (ENABLE_FEATURE_IPCALC_FANCY) {
 169                if (opt & NETPREFIX) {
 170                        printf("PREFIX=%i\n", get_prefix(netmask));
 171                }
 172
 173                if (opt & HOSTNAME) {
 174                        struct hostent *hostinfo;
 175
 176                        hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET);
 177                        if (!hostinfo) {
 178                                bb_herror_msg_and_die("can't find hostname for %s", argv[0]);
 179                        }
 180                        str_tolower(hostinfo->h_name);
 181
 182                        printf("HOSTNAME=%s\n", hostinfo->h_name);
 183                }
 184        }
 185
 186        return EXIT_SUCCESS;
 187}
 188