]> git.pld-linux.org Git - projects/rc-scripts.git/blame - src/ipcalc.c
- todo from arekm
[projects/rc-scripts.git] / src / ipcalc.c
CommitLineData
00196ec7
AM
1/*
2 * Copyright (c) 1997-2003 Red Hat, Inc. All rights reserved.
3 *
4 * This software may be freely redistributed under the terms of the GNU
5 * public license.
6 *
7 * You should have received a copy of the GNU General Public License
8 * along with this program; if not, write to the Free Software
9 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
10 *
11 * Authors:
12 * Erik Troan <ewt@redhat.com>
13 * Preston Brown <pbrown@redhat.com>
14 */
15
7743173d 16
00196ec7 17#include <ctype.h>
7742e157
AF
18#include <popt.h>
19#include <stdio.h>
00196ec7
AM
20#include <stdlib.h>
21#include <string.h>
7742e157 22#include <sys/socket.h>
00196ec7 23#include <sys/types.h>
7742e157
AF
24#include <netinet/in.h>
25#include <arpa/inet.h>
26#include <netdb.h>
27
00196ec7
AM
28/*!
29 \def IPBITS
30 \brief the number of bits in an IP address.
31*/
32#define IPBITS (sizeof(u_int32_t) * 8)
33/*!
34 \def IPBYTES
35 \brief the number of bytes in an IP address.
36*/
37#define IPBYTES (sizeof(u_int32_t))
7742e157 38
00196ec7
AM
39
40/*!
41 \file ipcalc.c
42 \brief provides utilities for manipulating IP addresses.
43
44 ipcalc provides utilities and a front-end command line interface for
45 manipulating IP addresses, and calculating various aspects of an ip
46 address/netmask/network address/prefix/etc.
47
48 Functionality can be accessed from other languages from the library
49 interface, documented here. To use ipcalc from the shell, read the
50 ipcalc(1) manual page.
51
52 When passing parameters to the various functions, take note of whether they
53 take host byte order or network byte order. Most take host byte order, and
54 return host byte order, but there are some exceptions.
55
56*/
57
58/*!
52471a31 59 \fn u_int32_t prefix2mask(int bits)
00196ec7
AM
60 \brief creates a netmask from a specified number of bits
61
62 This function converts a prefix length to a netmask. As CIDR (classless
63 internet domain internet domain routing) has taken off, more an more IP
64 addresses are being specified in the format address/prefix
65 (i.e. 192.168.2.3/24, with a corresponding netmask 255.255.255.0). If you
66 need to see what netmask corresponds to the prefix part of the address, this
67 is the function. See also \ref mask2prefix.
68
69 \param prefix is the number of bits to create a mask for.
70 \return a network mask, in network byte order.
71*/
52471a31 72u_int32_t prefix2mask(int prefix) {
00196ec7
AM
73 return htonl(~((1 << (32 - prefix)) - 1));
74}
75
76/*!
52471a31 77 \fn int mask2prefix(u_int32_t mask)
00196ec7
AM
78 \brief calculates the number of bits masked off by a netmask.
79
80 This function calculates the significant bits in an IP address as specified by
81 a netmask. See also \ref prefix2mask.
82
52471a31 83 \param mask is the netmask, specified as an u_int32_teger in network byte order.
00196ec7 84 \return the number of significant bits. */
52471a31 85int mask2prefix(u_int32_t mask)
00196ec7
AM
86{
87 int i;
88 int count = IPBITS;
89
90 for (i = 0; i < IPBITS; i++) {
91 if (!(ntohl(mask) & ((2 << i) - 1)))
92 count--;
93 }
94
95 return count;
96}
97
98/*!
52471a31 99 \fn u_int32_t default_netmask(u_int32_t addr)
00196ec7
AM
100
101 \brief returns the default (canonical) netmask associated with specified IP
102 address.
103
104 When the Internet was originally set up, various ranges of IP addresses were
105 segmented into three network classes: A, B, and C. This function will return
106 a netmask that is associated with the IP address specified defining where it
107 falls in the predefined classes.
108
109 \param addr an IP address in network byte order.
110 \return a netmask in network byte order. */
52471a31 111u_int32_t default_netmask(u_int32_t addr)
00196ec7
AM
112{
113 if (((ntohl(addr) & 0xFF000000) >> 24) <= 127)
114 return htonl(0xFF000000);
115 else if (((ntohl(addr) & 0xFF000000) >> 24) <= 191)
116 return htonl(0xFFFF0000);
117 else
118 return htonl(0xFFFFFF00);
119}
120
121/*!
52471a31 122 \fn u_int32_t calc_broadcast(u_int32_t addr, int prefix)
00196ec7
AM
123
124 \brief calculate broadcast address given an IP address and a prefix length.
125
126 \param addr an IP address in network byte order.
127 \param prefix a prefix length.
128
129 \return the calculated broadcast address for the network, in network byte
130 order.
131*/
52471a31 132u_int32_t calc_broadcast(u_int32_t addr,
00196ec7
AM
133 int prefix)
134{
135 return (addr & prefix2mask(prefix)) | ~prefix2mask(prefix);
136}
137
138/*!
52471a31 139 \fn u_int32_t calc_network(u_int32_t addr, int prefix)
00196ec7
AM
140 \brief calculates the network address for a specified address and prefix.
141
142 \param addr an IP address, in network byte order
143 \param prefix the network prefix
144 \return the base address of the network that addr is associated with, in
145 network byte order.
146*/
52471a31 147u_int32_t calc_network(u_int32_t addr, int prefix)
00196ec7
AM
148{
149 return (addr & prefix2mask(prefix));
150}
151
152/*!
52471a31 153 \fn const char *get_hostname(u_int32_t addr)
00196ec7
AM
154 \brief returns the hostname associated with the specified IP address
155
156 \param addr an IP address to find a hostname for, in network byte order
157
158 \return a hostname, or NULL if one cannot be determined. Hostname is stored
159 in a static buffer that may disappear at any time, the caller should copy the
160 data if it needs permanent storage.
161*/
52471a31 162const char *get_hostname(u_int32_t addr)
00196ec7
AM
163{
164 struct hostent * hostinfo;
165 int x;
166
167 hostinfo = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
168 if (!hostinfo)
169 return NULL;
170
171 for (x=0; hostinfo->h_name[x]; x++) {
172 hostinfo->h_name[x] = tolower(hostinfo->h_name[x]);
173 }
174 return hostinfo->h_name;
175}
176
177/*!
178 \fn main(int argc, const char **argv)
179 \brief wrapper program for ipcalc functions.
180
181 This is a wrapper program for the functions that the ipcalc library provides.
182 It can be used from shell scripts or directly from the command line.
183
184 For more information, please see the ipcalc(1) man page.
185*/
186int main(int argc, const char **argv) {
187 int showBroadcast = 0, showPrefix = 0, showNetwork = 0;
188 int showHostname = 0, showNetmask = 0;
7742e157
AF
189 int beSilent = 0;
190 int rc;
191 poptContext optCon;
00196ec7
AM
192 char *ipStr, *prefixStr, *netmaskStr, *hostName, *chptr;
193 struct in_addr ip, netmask, network, broadcast;
194 int prefix = 0;
7742e157
AF
195 char errBuf[250];
196 struct poptOption optionsTable[] = {
00196ec7
AM
197 { "broadcast", 'b', 0, &showBroadcast, 0,
198 "Display calculated broadcast address", },
199 { "hostname", 'h', 0, &showHostname, 0,
200 "Show hostname determined via DNS" },
201 { "netmask", 'm', 0, &showNetmask, 0,
202 "Display default netmask for IP (class A, B, or C)" },
203 { "network", 'n', 0, &showNetwork, 0,
204 "Display network address", },
205 { "prefix", 'p', 0, &showPrefix, 0,
206 "Display network prefix", },
207 { "silent", 's', 0, &beSilent, 0,
208 "Don't ever display error messages " },
209 POPT_AUTOHELP
210 { NULL, '\0', 0, 0, 0, NULL, NULL }
7742e157
AF
211 };
212
00196ec7 213 optCon = poptGetContext("ipcalc", argc, argv, optionsTable, 0);
7742e157
AF
214 poptReadDefaultConfig(optCon, 1);
215
216 if ((rc = poptGetNextOpt(optCon)) < -1) {
00196ec7 217 if (!beSilent) {
7742e157
AF
218 fprintf(stderr, "ipcalc: bad argument %s: %s\n",
219 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
220 poptStrerror(rc));
00196ec7
AM
221 poptPrintHelp(optCon, stderr, 0);
222 }
7742e157
AF
223 return 1;
224 }
225
00196ec7
AM
226 if (!(ipStr = (char *) poptGetArg(optCon))) {
227 if (!beSilent) {
7742e157 228 fprintf(stderr, "ipcalc: ip address expected\n");
00196ec7
AM
229 poptPrintHelp(optCon, stderr, 0);
230 }
7742e157
AF
231 return 1;
232 }
233
00196ec7
AM
234 if (strchr(ipStr,'/') != NULL) {
235 prefixStr = strchr(ipStr, '/') + 1;
236 prefixStr--;
237 *prefixStr = '\0'; /* fix up ipStr */
238 prefixStr++;
239 } else
240 prefixStr = NULL;
241
242 if (prefixStr != NULL) {
243 prefix = atoi(prefixStr);
244 if (prefix == 0) {
7742e157 245 if (!beSilent)
00196ec7
AM
246 fprintf(stderr, "ipcalc: bad prefix: %s\n",
247 prefixStr);
7742e157
AF
248 return 1;
249 }
00196ec7
AM
250 }
251
252 if (showBroadcast || showNetwork || showPrefix) {
253 if (!(netmaskStr = (char *) poptGetArg(optCon)) &&
254 (prefix == 0)) {
255 if (!beSilent) {
256 fprintf(stderr, "ipcalc: netmask or prefix expected\n");
257 poptPrintHelp(optCon, stderr, 0);
258 }
259 return 1;
260 } else if (netmaskStr && prefix != 0) {
261 if (!beSilent) {
262 fprintf(stderr, "ipcalc: both netmask and prefix specified\n");
263 poptPrintHelp(optCon, stderr, 0);
264 }
7742e157 265 return 1;
00196ec7
AM
266 } else if (netmaskStr) {
267 if (!inet_aton(netmaskStr, &netmask)) {
268 if (!beSilent)
269 fprintf(stderr, "ipcalc: bad netmask: %s\n",
270 netmaskStr);
271 return 1;
272 }
273 prefix = mask2prefix(netmask.s_addr);
7742e157
AF
274 }
275 }
276
00196ec7
AM
277 if ((chptr = (char *) poptGetArg(optCon))) {
278 if (!beSilent) {
7742e157 279 fprintf(stderr, "ipcalc: unexpected argument: %s\n", chptr);
00196ec7
AM
280 poptPrintHelp(optCon, stderr, 0);
281 }
7742e157
AF
282 return 1;
283 }
284
00196ec7
AM
285 /* Handle CIDR entries such as 172/8 */
286 if (prefix) {
287 char *tmp = ipStr;
288 int i;
289
290 for(i=3; i> 0; i--) {
291 tmp = strchr(tmp,'.');
292 if (!tmp)
293 break;
294 else
295 tmp++;
296 }
297 tmp = NULL;
298 for (; i>0; i--) {
299 tmp = malloc(strlen(ipStr) + 3);
300 sprintf(tmp,"%s.0",ipStr);
301 ipStr = tmp;
302 }
303 }
7742e157
AF
304
305 if (!inet_aton(ipStr, (struct in_addr *) &ip)) {
306 if (!beSilent)
307 fprintf(stderr, "ipcalc: bad ip address: %s\n", ipStr);
308 return 1;
309 }
310
00196ec7
AM
311
312 if (!(showNetmask|showPrefix|showBroadcast|showNetwork|showHostname)) {
313 poptPrintHelp(optCon, stderr, 0);
314 return 1;
315 }
316
317 poptFreeContext(optCon);
318
319 /* we know what we want to display now, so display it. */
64e79ccb 320
7742e157 321 if (showNetmask) {
00196ec7
AM
322 if (prefix) {
323 netmask.s_addr = prefix2mask(prefix);
64e79ccb 324 } else {
00196ec7
AM
325 netmask.s_addr = default_netmask(ip.s_addr);
326 prefix = mask2prefix(netmask.s_addr);
64e79ccb 327 }
7742e157 328
00196ec7 329 printf("NETMASK=%s\n", inet_ntoa(netmask));
7742e157
AF
330 }
331
00196ec7
AM
332 if (showPrefix) {
333 if (!prefix)
334 prefix = mask2prefix(ip.s_addr);
335 printf("PREFIX=%d\n", prefix);
336 }
337
7742e157 338 if (showBroadcast) {
00196ec7
AM
339 broadcast.s_addr = calc_broadcast(ip.s_addr, prefix);
340 printf("BROADCAST=%s\n", inet_ntoa(broadcast));
7742e157
AF
341 }
342
343 if (showNetwork) {
00196ec7
AM
344 network.s_addr = calc_network(ip.s_addr, prefix);
345 printf("NETWORK=%s\n", inet_ntoa(network));
7742e157 346 }
00196ec7
AM
347
348 if (showHostname) {
349 if ((hostName = (char *) get_hostname(ip.s_addr)) == NULL) {
7742e157
AF
350 if (!beSilent) {
351 sprintf(errBuf, "ipcalc: cannot find hostname for %s", ipStr);
352 herror(errBuf);
353 }
7742e157
AF
354 return 1;
355 }
00196ec7
AM
356
357 printf("HOSTNAME=%s\n", hostName);
7742e157
AF
358 }
359
7742e157
AF
360 return 0;
361}
This page took 0.11842 seconds and 4 git commands to generate.