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