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 tarball for details. 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