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