blob: e82e35dd5951acd70d3e94297cdcf860760e173e [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrathc11986d2002-11-10 23:42:27 +00002/*
3 * Mini ipcalc implementation for busybox
4 *
5 * By Jordan Crouse <jordan@cosmicpenguin.net>
6 * Stephan Linz <linz@li-pro.net>
7 *
Eric Andersenaff114c2004-04-14 17:51:38 +00008 * This is a complete reimplementation of the ipcalc program
9 * from Red Hat. I didn't look at their source code, but there
Glenn L McGrathc11986d2002-11-10 23:42:27 +000010 * is no denying that this is a loving reimplementation
Bernhard Reutner-Fischerb1629b12006-05-19 19:29:19 +000011 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020012 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrathc11986d2002-11-10 23:42:27 +000013 */
Denys Vlasenko47367e12016-11-23 09:05:14 +010014//config:config IPCALC
Denys Vlasenkob097a842018-12-28 03:20:17 +010015//config: bool "ipcalc (4.4 kb)"
Denys Vlasenko47367e12016-11-23 09:05:14 +010016//config: default y
17//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020018//config: ipcalc takes an IP address and netmask and calculates the
19//config: resulting broadcast, network, and host range.
Denys Vlasenko47367e12016-11-23 09:05:14 +010020//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010021//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:
Denys Vlasenko47367e12016-11-23 09:05:14 +010026//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
Denys Vlasenko72089cf2017-07-21 09:50:55 +020031//config: Adds the options hostname, prefix and silent to the output of
32//config: "ipcalc".
Denys Vlasenko47367e12016-11-23 09:05:14 +010033
Denys Vlasenko90ad4ba2017-08-08 00:42:15 +020034//applet:IF_IPCALC(APPLET_NOEXEC(ipcalc, ipcalc, BB_DIR_BIN, BB_SUID_DROP, ipcalc))
Denys Vlasenko47367e12016-11-23 09:05:14 +010035
36//kbuild:lib-$(CONFIG_IPCALC) += ipcalc.o
Pere Orga5bc8c002011-04-11 03:29:49 +020037
38//usage:#define ipcalc_trivial_usage
Denys Vlasenko84d5edd2020-12-13 22:34:05 +010039//usage: "[-bnm"IF_FEATURE_IPCALC_FANCY("phs")"] ADDRESS"
Ron Yorston72dcbe42015-07-12 21:19:28 +010040//usage: IF_FEATURE_IPCALC_FANCY("[/PREFIX]") " [NETMASK]"
Pere Orga5bc8c002011-04-11 03:29:49 +020041//usage:#define ipcalc_full_usage "\n\n"
Denys Vlasenko73adef12017-08-08 00:49:48 +020042//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"
Pere Orga5bc8c002011-04-11 03:29:49 +020046//usage: IF_FEATURE_IPCALC_FANCY(
Denys Vlasenko73adef12017-08-08 00:49:48 +020047//usage: "\n -p Prefix for IP/NETMASK"
48//usage: "\n -h Resolved host name"
49//usage: "\n -s No error messages"
Pere Orga5bc8c002011-04-11 03:29:49 +020050//usage: )
51
Dan Fandrichfdd7b562010-06-18 22:37:42 -070052#include "libbb.h"
Denys Vlasenko134d0eb2010-06-19 20:07:23 +020053/* After libbb.h, because on some systems it needs other includes */
Glenn L McGrathc11986d2002-11-10 23:42:27 +000054#include <arpa/inet.h>
55
Denys Vlasenkofb132e42010-10-29 11:46:52 +020056#define CLASS_A_NETMASK ntohl(0xFF000000)
57#define CLASS_B_NETMASK ntohl(0xFFFF0000)
58#define CLASS_C_NETMASK ntohl(0xFFFFFF00)
Eric Andersen7207b882003-07-05 07:59:30 +000059
Glenn L McGrathc11986d2002-11-10 23:42:27 +000060static unsigned long get_netmask(unsigned long ipaddr)
61{
Eric Andersen7207b882003-07-05 07:59:30 +000062 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;
Glenn L McGrathc11986d2002-11-10 23:42:27 +000072}
73
Denis Vlasenkoe3241842007-08-13 10:36:25 +000074#if ENABLE_FEATURE_IPCALC_FANCY
Glenn L McGrath530ea422003-09-02 06:59:57 +000075static int get_prefix(unsigned long netmask)
76{
Glenn L McGrath14092a12003-09-12 00:44:50 +000077 unsigned long msk = 0x80000000;
Eric Andersena4375042004-04-13 19:25:57 +000078 int ret = 0;
Glenn L McGrath530ea422003-09-02 06:59:57 +000079
Glenn L McGrath14092a12003-09-12 00:44:50 +000080 netmask = htonl(netmask);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000081 while (msk) {
Glenn L McGrath14092a12003-09-12 00:44:50 +000082 if (netmask & msk)
83 ret++;
84 msk >>= 1;
Eric Andersena4375042004-04-13 19:25:57 +000085 }
86 return ret;
Glenn L McGrath530ea422003-09-02 06:59:57 +000087}
Rob Landleyff97ee92006-06-02 19:03:01 +000088#else
89int get_prefix(unsigned long netmask);
Glenn L McGrath530ea422003-09-02 06:59:57 +000090#endif
91
Denis Vlasenko13858992006-10-08 12:49:22 +000092
Glenn L McGrathc11986d2002-11-10 23:42:27 +000093#define NETMASK 0x01
94#define BROADCAST 0x02
95#define NETWORK 0x04
Glenn L McGrath530ea422003-09-02 06:59:57 +000096#define NETPREFIX 0x08
97#define HOSTNAME 0x10
Glenn L McGrathd6bdd5d2003-09-05 02:37:15 +000098#define SILENT 0x20
Glenn L McGrathc11986d2002-11-10 23:42:27 +000099
Bernhard Reutner-Fischer01d23ad2006-05-26 20:19:22 +0000100#if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000101 static const char ipcalc_longopts[] ALIGN1 =
Steve Bennett823b6362010-04-07 19:16:12 +0200102 "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]
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000105# if ENABLE_FEATURE_IPCALC_FANCY
Steve Bennett823b6362010-04-07 19:16:12 +0200106 "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
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000109# endif
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000110 ;
Denys Vlasenko036585a2017-08-08 16:38:18 +0200111# define GETOPT32 getopt32long
112# define LONGOPTS ,ipcalc_longopts
113#else
114# define GETOPT32 getopt32
115# define LONGOPTS
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000116#endif
Denis Vlasenkoc61852a2006-11-29 11:09:43 +0000117
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000118int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100119int ipcalc_main(int argc UNUSED_PARAM, char **argv)
Rob Landleyff97ee92006-06-02 19:03:01 +0000120{
Denis Vlasenko13858992006-10-08 12:49:22 +0000121 unsigned opt;
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100122 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)
Rob Landleyff97ee92006-06-02 19:03:01 +0000131 char *ipstr;
132
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200133 opt = GETOPT32(argv, "^"
134 "mbn" IF_FEATURE_IPCALC_FANCY("phs")
135 "\0" "-1:?2"/*min 1, max 2 args*/
136 LONGOPTS
137 );
Mike Frysingerb7f88e02005-09-24 23:48:18 +0000138 argv += optind;
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100139 if (opt & SILENT)
140 logmode = LOGMODE_NONE; /* suppress error_msg() output */
Steve Bennett823b6362010-04-07 19:16:12 +0200141 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])
Manuel Novoa III cad53642003-03-19 09:13:01 +0000146 bb_show_usage();
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000147 }
148
Rob Landleyff97ee92006-06-02 19:03:01 +0000149 ipstr = argv[0];
150 if (ENABLE_FEATURE_IPCALC_FANCY) {
151 unsigned long netprefix = 0;
152 char *prefixstr;
Glenn L McGrath530ea422003-09-02 06:59:57 +0000153
Rob Landleyff97ee92006-06-02 19:03:01 +0000154 prefixstr = ipstr;
Glenn L McGrath14092a12003-09-12 00:44:50 +0000155
Denis Vlasenko13858992006-10-08 12:49:22 +0000156 while (*prefixstr) {
Rob Landleyff97ee92006-06-02 19:03:01 +0000157 if (*prefixstr == '/') {
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100158 *prefixstr++ = '\0';
Rob Landleyff97ee92006-06-02 19:03:01 +0000159 if (*prefixstr) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000160 unsigned msk;
161 netprefix = xatoul_range(prefixstr, 0, 32);
Rob Landleyff97ee92006-06-02 19:03:01 +0000162 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;
Eric Andersena4375042004-04-13 19:25:57 +0000173 }
Rob Landleyff97ee92006-06-02 19:03:01 +0000174 break;
Eric Andersena4375042004-04-13 19:25:57 +0000175 }
Rob Landleyff97ee92006-06-02 19:03:01 +0000176 prefixstr++;
Eric Andersena4375042004-04-13 19:25:57 +0000177 }
Eric Andersena4375042004-04-13 19:25:57 +0000178 }
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000179
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100180 if (inet_aton(ipstr, &s_ipaddr) == 0) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000181 bb_error_msg_and_die("bad IP address: %s", argv[0]);
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000182 }
183
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100184 if (argv[1]) {
Rob Landleyff97ee92006-06-02 19:03:01 +0000185 if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) {
James Byrne69374872019-07-02 11:35:03 +0200186 bb_simple_error_msg_and_die("use prefix or netmask, not both");
Eric Andersena4375042004-04-13 19:25:57 +0000187 }
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100188 if (inet_aton(argv[1], &s_netmask) == 0) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000189 bb_error_msg_and_die("bad netmask: %s", argv[1]);
Eric Andersena4375042004-04-13 19:25:57 +0000190 }
Glenn L McGrath14092a12003-09-12 00:44:50 +0000191 } else {
Rob Landleyff97ee92006-06-02 19:03:01 +0000192 /* JHC - If the netmask wasn't provided then calculate it */
193 if (!ENABLE_FEATURE_IPCALC_FANCY || !have_netmask)
Eric Andersena4375042004-04-13 19:25:57 +0000194 netmask = get_netmask(ipaddr);
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000195 }
196
Denis Vlasenko13858992006-10-08 12:49:22 +0000197 if (opt & NETMASK) {
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100198 printf("NETMASK=%s\n", inet_ntoa(s_netmask));
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000199 }
200
Denis Vlasenko13858992006-10-08 12:49:22 +0000201 if (opt & BROADCAST) {
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000202 broadcast = (ipaddr & netmask) | ~netmask;
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100203 printf("BROADCAST=%s\n", inet_ntoa(s_broadcast));
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000204 }
205
Denis Vlasenko13858992006-10-08 12:49:22 +0000206 if (opt & NETWORK) {
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000207 network = ipaddr & netmask;
Denys Vlasenko12ca0802010-02-04 18:41:18 +0100208 printf("NETWORK=%s\n", inet_ntoa(s_network));
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000209 }
Glenn L McGrath530ea422003-09-02 06:59:57 +0000210
Rob Landleyff97ee92006-06-02 19:03:01 +0000211 if (ENABLE_FEATURE_IPCALC_FANCY) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000212 if (opt & NETPREFIX) {
Rob Landleyff97ee92006-06-02 19:03:01 +0000213 printf("PREFIX=%i\n", get_prefix(netmask));
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000214 }
215
Denis Vlasenko13858992006-10-08 12:49:22 +0000216 if (opt & HOSTNAME) {
Rob Landleyff97ee92006-06-02 19:03:01 +0000217 struct hostent *hostinfo;
Rob Landleyff97ee92006-06-02 19:03:01 +0000218
219 hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET);
220 if (!hostinfo) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100221 bb_herror_msg_and_die("can't find hostname for %s", argv[0]);
Rob Landleyff97ee92006-06-02 19:03:01 +0000222 }
Denis Vlasenkofcc63472008-04-10 02:09:40 +0000223 str_tolower(hostinfo->h_name);
Denis Vlasenko5b3adae2008-04-19 21:57:57 +0000224
Rob Landleyff97ee92006-06-02 19:03:01 +0000225 printf("HOSTNAME=%s\n", hostinfo->h_name);
226 }
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000227 }
Glenn L McGrathc11986d2002-11-10 23:42:27 +0000228
229 return EXIT_SUCCESS;
230}