source: projects/initscripts/tags/initscripts-8.91.3/src/ipcalc.c @ 1108

Revision 1108, 10.0 KB checked in by daisuke, 14 years ago (diff)

import initscripts-8.90.6 from internal cvs repository

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