| /* vi: set sw=4 ts=4: */ | 
 | /* | 
 |  * Mini ipcalc implementation for busybox | 
 |  * | 
 |  * By Jordan Crouse <jordan@cosmicpenguin.net> | 
 |  *    Stephan Linz  <linz@li-pro.net> | 
 |  * | 
 |  * This is a complete reimplementation of the ipcalc program | 
 |  * from Red Hat.  I didn't look at their source code, but there | 
 |  * is no denying that this is a loving reimplementation | 
 |  * | 
 |  * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 
 |  */ | 
 |  | 
 | //usage:#define ipcalc_trivial_usage | 
 | //usage:       "[OPTIONS] ADDRESS[[/]NETMASK] [NETMASK]" | 
 | //usage:#define ipcalc_full_usage "\n\n" | 
 | //usage:       "Calculate IP network settings from a IP address\n" | 
 | //usage:	IF_FEATURE_IPCALC_LONG_OPTIONS( | 
 | //usage:     "\n	-b,--broadcast	Display calculated broadcast address" | 
 | //usage:     "\n	-n,--network	Display calculated network address" | 
 | //usage:     "\n	-m,--netmask	Display default netmask for IP" | 
 | //usage:	IF_FEATURE_IPCALC_FANCY( | 
 | //usage:     "\n	-p,--prefix	Display the prefix for IP/NETMASK" | 
 | //usage:     "\n	-h,--hostname	Display first resolved host name" | 
 | //usage:     "\n	-s,--silent	Don't ever display error messages" | 
 | //usage:	) | 
 | //usage:	) | 
 | //usage:	IF_NOT_FEATURE_IPCALC_LONG_OPTIONS( | 
 | //usage:     "\n	-b	Display calculated broadcast address" | 
 | //usage:     "\n	-n	Display calculated network address" | 
 | //usage:     "\n	-m	Display default netmask for IP" | 
 | //usage:	IF_FEATURE_IPCALC_FANCY( | 
 | //usage:     "\n	-p	Display the prefix for IP/NETMASK" | 
 | //usage:     "\n	-h	Display first resolved host name" | 
 | //usage:     "\n	-s	Don't ever display error messages" | 
 | //usage:	) | 
 | //usage:	) | 
 |  | 
 | #include "libbb.h" | 
 | /* After libbb.h, because on some systems it needs other includes */ | 
 | #include <arpa/inet.h> | 
 |  | 
 | #define CLASS_A_NETMASK ntohl(0xFF000000) | 
 | #define CLASS_B_NETMASK ntohl(0xFFFF0000) | 
 | #define CLASS_C_NETMASK ntohl(0xFFFFFF00) | 
 |  | 
 | static unsigned long get_netmask(unsigned long ipaddr) | 
 | { | 
 | 	ipaddr = htonl(ipaddr); | 
 |  | 
 | 	if ((ipaddr & 0xC0000000) == 0xC0000000) | 
 | 		return CLASS_C_NETMASK; | 
 | 	else if ((ipaddr & 0x80000000) == 0x80000000) | 
 | 		return CLASS_B_NETMASK; | 
 | 	else if ((ipaddr & 0x80000000) == 0) | 
 | 		return CLASS_A_NETMASK; | 
 | 	else | 
 | 		return 0; | 
 | } | 
 |  | 
 | #if ENABLE_FEATURE_IPCALC_FANCY | 
 | static int get_prefix(unsigned long netmask) | 
 | { | 
 | 	unsigned long msk = 0x80000000; | 
 | 	int ret = 0; | 
 |  | 
 | 	netmask = htonl(netmask); | 
 | 	while (msk) { | 
 | 		if (netmask & msk) | 
 | 			ret++; | 
 | 		msk >>= 1; | 
 | 	} | 
 | 	return ret; | 
 | } | 
 | #else | 
 | int get_prefix(unsigned long netmask); | 
 | #endif | 
 |  | 
 |  | 
 | #define NETMASK   0x01 | 
 | #define BROADCAST 0x02 | 
 | #define NETWORK   0x04 | 
 | #define NETPREFIX 0x08 | 
 | #define HOSTNAME  0x10 | 
 | #define SILENT    0x20 | 
 |  | 
 | #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS | 
 | 	static const char ipcalc_longopts[] ALIGN1 = | 
 | 		"netmask\0"   No_argument "m" // netmask from IP (assuming complete class A, B, or C network) | 
 | 		"broadcast\0" No_argument "b" // broadcast from IP [netmask] | 
 | 		"network\0"   No_argument "n" // network from IP [netmask] | 
 | # if ENABLE_FEATURE_IPCALC_FANCY | 
 | 		"prefix\0"    No_argument "p" // prefix from IP[/prefix] [netmask] | 
 | 		"hostname\0"  No_argument "h" // hostname from IP | 
 | 		"silent\0"    No_argument "s" // don’t ever display error messages | 
 | # endif | 
 | 		; | 
 | #endif | 
 |  | 
 | int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 
 | int ipcalc_main(int argc UNUSED_PARAM, char **argv) | 
 | { | 
 | 	unsigned opt; | 
 | 	bool have_netmask = 0; | 
 | 	struct in_addr s_netmask, s_broadcast, s_network, s_ipaddr; | 
 | 	/* struct in_addr { in_addr_t s_addr; }  and  in_addr_t | 
 | 	 * (which in turn is just a typedef to uint32_t) | 
 | 	 * are essentially the same type. A few macros for less verbosity: */ | 
 | #define netmask   (s_netmask.s_addr) | 
 | #define broadcast (s_broadcast.s_addr) | 
 | #define network   (s_network.s_addr) | 
 | #define ipaddr    (s_ipaddr.s_addr) | 
 | 	char *ipstr; | 
 |  | 
 | #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS | 
 | 	applet_long_options = ipcalc_longopts; | 
 | #endif | 
 | 	opt_complementary = "-1:?2"; /* minimum 1 arg, maximum 2 args */ | 
 | 	opt = getopt32(argv, "mbn" IF_FEATURE_IPCALC_FANCY("phs")); | 
 | 	argv += optind; | 
 | 	if (opt & SILENT) | 
 | 		logmode = LOGMODE_NONE; /* suppress error_msg() output */ | 
 | 	opt &= ~SILENT; | 
 | 	if (!(opt & (BROADCAST | NETWORK | NETPREFIX))) { | 
 | 		/* if no options at all or | 
 | 		 * (no broadcast,network,prefix) and (two args)... */ | 
 | 		if (!opt || argv[1]) | 
 | 			bb_show_usage(); | 
 | 	} | 
 |  | 
 | 	ipstr = argv[0]; | 
 | 	if (ENABLE_FEATURE_IPCALC_FANCY) { | 
 | 		unsigned long netprefix = 0; | 
 | 		char *prefixstr; | 
 |  | 
 | 		prefixstr = ipstr; | 
 |  | 
 | 		while (*prefixstr) { | 
 | 			if (*prefixstr == '/') { | 
 | 				*prefixstr++ = '\0'; | 
 | 				if (*prefixstr) { | 
 | 					unsigned msk; | 
 | 					netprefix = xatoul_range(prefixstr, 0, 32); | 
 | 					netmask = 0; | 
 | 					msk = 0x80000000; | 
 | 					while (netprefix > 0) { | 
 | 						netmask |= msk; | 
 | 						msk >>= 1; | 
 | 						netprefix--; | 
 | 					} | 
 | 					netmask = htonl(netmask); | 
 | 					/* Even if it was 0, we will signify that we have a netmask. This allows */ | 
 | 					/* for specification of default routes, etc which have a 0 netmask/prefix */ | 
 | 					have_netmask = 1; | 
 | 				} | 
 | 				break; | 
 | 			} | 
 | 			prefixstr++; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (inet_aton(ipstr, &s_ipaddr) == 0) { | 
 | 		bb_error_msg_and_die("bad IP address: %s", argv[0]); | 
 | 	} | 
 |  | 
 | 	if (argv[1]) { | 
 | 		if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) { | 
 | 			bb_error_msg_and_die("use prefix or netmask, not both"); | 
 | 		} | 
 | 		if (inet_aton(argv[1], &s_netmask) == 0) { | 
 | 			bb_error_msg_and_die("bad netmask: %s", argv[1]); | 
 | 		} | 
 | 	} else { | 
 | 		/* JHC - If the netmask wasn't provided then calculate it */ | 
 | 		if (!ENABLE_FEATURE_IPCALC_FANCY || !have_netmask) | 
 | 			netmask = get_netmask(ipaddr); | 
 | 	} | 
 |  | 
 | 	if (opt & NETMASK) { | 
 | 		printf("NETMASK=%s\n", inet_ntoa(s_netmask)); | 
 | 	} | 
 |  | 
 | 	if (opt & BROADCAST) { | 
 | 		broadcast = (ipaddr & netmask) | ~netmask; | 
 | 		printf("BROADCAST=%s\n", inet_ntoa(s_broadcast)); | 
 | 	} | 
 |  | 
 | 	if (opt & NETWORK) { | 
 | 		network = ipaddr & netmask; | 
 | 		printf("NETWORK=%s\n", inet_ntoa(s_network)); | 
 | 	} | 
 |  | 
 | 	if (ENABLE_FEATURE_IPCALC_FANCY) { | 
 | 		if (opt & NETPREFIX) { | 
 | 			printf("PREFIX=%i\n", get_prefix(netmask)); | 
 | 		} | 
 |  | 
 | 		if (opt & HOSTNAME) { | 
 | 			struct hostent *hostinfo; | 
 |  | 
 | 			hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET); | 
 | 			if (!hostinfo) { | 
 | 				bb_herror_msg_and_die("can't find hostname for %s", argv[0]); | 
 | 			} | 
 | 			str_tolower(hostinfo->h_name); | 
 |  | 
 | 			printf("HOSTNAME=%s\n", hostinfo->h_name); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return EXIT_SUCCESS; | 
 | } |