ade4ed101559d8145cf5d2832da7037a2e893cb7
[oweals/busybox.git] / networking / ipcalc.c
1 /* vi: set sw=4 ts=4 ai: */
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 <stdio.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include <getopt.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22
23 #include "busybox.h"
24
25 #define IPCALC_MSG(CMD,ALTCMD) if (mode & SILENT) {ALTCMD;} else {CMD;}
26
27 #define CLASS_A_NETMASK ntohl(0xFF000000)
28 #define CLASS_B_NETMASK ntohl(0xFFFF0000)
29 #define CLASS_C_NETMASK ntohl(0xFFFFFF00)
30
31 static unsigned long get_netmask(unsigned long ipaddr)
32 {
33         ipaddr = htonl(ipaddr);
34
35         if ((ipaddr & 0xC0000000) == 0xC0000000)
36                 return CLASS_C_NETMASK;
37         else if ((ipaddr & 0x80000000) == 0x80000000)
38                 return CLASS_B_NETMASK;
39         else if ((ipaddr & 0x80000000) == 0)
40                 return CLASS_A_NETMASK;
41         else
42                 return 0;
43 }
44
45 #ifdef CONFIG_FEATURE_IPCALC_FANCY
46 static int get_prefix(unsigned long netmask)
47 {
48         unsigned long msk = 0x80000000;
49         int ret = 0;
50
51         netmask = htonl(netmask);
52         while(msk) {
53                 if (netmask & msk)
54                         ret++;
55                 msk >>= 1;
56         }
57         return ret;
58 }
59 #endif
60
61 #define NETMASK   0x01
62 #define BROADCAST 0x02
63 #define NETWORK   0x04
64 #define NETPREFIX 0x08
65 #define HOSTNAME  0x10
66 #define SILENT    0x20
67
68
69 int ipcalc_main(int argc, char **argv)
70 {
71         unsigned long mode;
72
73         in_addr_t netmask;
74         in_addr_t broadcast;
75         in_addr_t network;
76         in_addr_t ipaddr;
77         struct in_addr a;
78
79 #ifdef CONFIG_FEATURE_IPCALC_FANCY
80         unsigned long netprefix = 0;
81         int have_netmask = 0;
82         char *ipstr, *prefixstr;
83 #endif
84
85 #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
86         static const struct option long_options[] = {
87                 {"netmask",             no_argument, NULL, 'm'},
88                 {"broadcast",   no_argument, NULL, 'b'},
89                 {"network",             no_argument, NULL, 'n'},
90 #ifdef CONFIG_FEATURE_IPCALC_FANCY
91                 {"prefix",              no_argument, NULL, 'p'},
92                 {"hostname",    no_argument, NULL, 'h'},
93                 {"silent",              no_argument, NULL, 's'},
94 #endif
95                 {NULL, 0, NULL, 0}
96         };
97
98         bb_applet_long_options = long_options;
99 #endif
100         mode = bb_getopt_ulflags(argc, argv,
101 #ifdef CONFIG_FEATURE_IPCALC_FANCY
102                         "mbnphs"
103 #else
104                         "mbn"
105 #endif
106                         );
107
108         argc -= optind;
109         argv += optind;
110         if (mode & (BROADCAST | NETWORK | NETPREFIX)) {
111                 if (argc > 2 || argc <= 0)
112                         bb_show_usage();
113         } else {
114                 if (argc != 1)
115                         bb_show_usage();
116         }
117
118 #ifdef CONFIG_FEATURE_IPCALC_FANCY
119         prefixstr = ipstr = argv[0];
120
121         while(*prefixstr) {
122                 if (*prefixstr == '/') {
123                         *prefixstr = (char)0;
124                         prefixstr++;
125                         if (*prefixstr) {
126                                 unsigned int msk;
127
128                                 if (safe_strtoul(prefixstr, &netprefix) || netprefix > 32) {
129                                         IPCALC_MSG(bb_error_msg_and_die("bad IP prefix: %s\n", prefixstr),
130                                                         exit(EXIT_FAILURE));
131                                 }
132                                 netmask = 0;
133                                 msk = 0x80000000;
134                                 while (netprefix > 0) {
135                                         netmask |= msk;
136                                         msk >>= 1;
137                                         netprefix--;
138                                 }
139                                 netmask = htonl(netmask);
140                                 /* Even if it was 0, we will signify that we have a netmask. This allows */
141                                 /* for specification of default routes, etc which have a 0 netmask/prefix */
142                                 have_netmask = 1;
143                         }
144                         break;
145                 }
146                 prefixstr++;
147         }
148         ipaddr = inet_aton(ipstr, &a);
149 #else
150         ipaddr = inet_aton(argv[0], &a);
151 #endif
152
153         if (ipaddr == 0) {
154                 IPCALC_MSG(bb_error_msg_and_die("bad IP address: %s", argv[0]),
155                                 exit(EXIT_FAILURE));
156         }
157         ipaddr = a.s_addr;
158
159         if (argc == 2) {
160 #ifdef CONFIG_FEATURE_IPCALC_FANCY
161                 if (have_netmask) {
162                         IPCALC_MSG(bb_error_msg_and_die("Both prefix and netmask were specified, use one or the other.\n"),
163                                         exit(EXIT_FAILURE));
164                 }
165
166 #endif
167                 netmask = inet_aton(argv[1], &a);
168                 if (netmask == 0) {
169                         IPCALC_MSG(bb_error_msg_and_die("bad netmask: %s", argv[1]),
170                                         exit(EXIT_FAILURE));
171                 }
172                 netmask = a.s_addr;
173         } else {
174 #ifdef CONFIG_FEATURE_IPCALC_FANCY
175
176                 if (!have_netmask)
177 #endif
178                         /* JHC - If the netmask wasn't provided then calculate it */
179                         netmask = get_netmask(ipaddr);
180         }
181
182         if (mode & NETMASK) {
183                 printf("NETMASK=%s\n", inet_ntoa((*(struct in_addr *) &netmask)));
184         }
185
186         if (mode & BROADCAST) {
187                 broadcast = (ipaddr & netmask) | ~netmask;
188                 printf("BROADCAST=%s\n", inet_ntoa((*(struct in_addr *) &broadcast)));
189         }
190
191         if (mode & NETWORK) {
192                 network = ipaddr & netmask;
193                 printf("NETWORK=%s\n", inet_ntoa((*(struct in_addr *) &network)));
194         }
195
196 #ifdef CONFIG_FEATURE_IPCALC_FANCY
197         if (mode & NETPREFIX) {
198                 printf("PREFIX=%i\n", get_prefix(netmask));
199         }
200
201         if (mode & HOSTNAME) {
202                 struct hostent *hostinfo;
203                 int x;
204
205                 hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET);
206                 if (!hostinfo) {
207                         IPCALC_MSG(bb_herror_msg_and_die(
208                                                 "cannot find hostname for %s", argv[0]),);
209                         exit(EXIT_FAILURE);
210                 }
211                 for (x = 0; hostinfo->h_name[x]; x++) {
212                         hostinfo->h_name[x] = tolower(hostinfo->h_name[x]);
213                 }
214
215                 printf("HOSTNAME=%s\n", hostinfo->h_name);
216         }
217 #endif
218
219         return EXIT_SUCCESS;
220 }