2 * Copyright (c) 1997-2003 Red Hat, Inc. All rights reserved.
4 * This software may be freely redistributed under the terms of the GNU
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.
12 * Erik Troan <ewt@redhat.com>
13 * Preston Brown <pbrown@redhat.com>
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
30 \brief the number of bits in an IP address.
32 #define IPBITS (sizeof(u_int32_t) * 8)
35 \brief the number of bytes in an IP address.
37 #define IPBYTES (sizeof(u_int32_t))
42 \brief provides utilities for manipulating IP addresses.
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.
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.
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.
59 \fn u_int32_t prefix2mask(int bits)
60 \brief creates a netmask from a specified number of bits
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.
69 \param prefix is the number of bits to create a mask for.
70 \return a network mask, in network byte order.
72 u_int32_t prefix2mask(int prefix) {
73 return htonl(~((1 << (32 - prefix)) - 1));
77 \fn int mask2prefix(u_int32_t mask)
78 \brief calculates the number of bits masked off by a netmask.
80 This function calculates the significant bits in an IP address as specified by
81 a netmask. See also \ref prefix2mask.
83 \param mask is the netmask, specified as an u_int32_teger in network byte order.
84 \return the number of significant bits. */
85 int mask2prefix(u_int32_t mask)
90 for (i = 0; i < IPBITS; i++) {
91 if (!(ntohl(mask) & ((2 << i) - 1)))
99 \fn u_int32_t default_netmask(u_int32_t addr)
101 \brief returns the default (canonical) netmask associated with specified IP
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.
109 \param addr an IP address in network byte order.
110 \return a netmask in network byte order. */
111 u_int32_t default_netmask(u_int32_t addr)
113 if (((ntohl(addr) & 0xFF000000) >> 24) <= 127)
114 return htonl(0xFF000000);
115 else if (((ntohl(addr) & 0xFF000000) >> 24) <= 191)
116 return htonl(0xFFFF0000);
118 return htonl(0xFFFFFF00);
122 \fn u_int32_t calc_broadcast(u_int32_t addr, int prefix)
124 \brief calculate broadcast address given an IP address and a prefix length.
126 \param addr an IP address in network byte order.
127 \param prefix a prefix length.
129 \return the calculated broadcast address for the network, in network byte
132 u_int32_t calc_broadcast(u_int32_t addr,
135 return (addr & prefix2mask(prefix)) | ~prefix2mask(prefix);
139 \fn u_int32_t calc_network(u_int32_t addr, int prefix)
140 \brief calculates the network address for a specified address and prefix.
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
147 u_int32_t calc_network(u_int32_t addr, int prefix)
149 return (addr & prefix2mask(prefix));
153 \fn const char *get_hostname(u_int32_t addr)
154 \brief returns the hostname associated with the specified IP address
156 \param addr an IP address to find a hostname for, in network byte order
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.
162 const char *get_hostname(u_int32_t addr)
164 struct hostent * hostinfo;
167 hostinfo = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
171 for (x=0; hostinfo->h_name[x]; x++) {
172 hostinfo->h_name[x] = tolower(hostinfo->h_name[x]);
174 return hostinfo->h_name;
178 \fn main(int argc, const char **argv)
179 \brief wrapper program for ipcalc functions.
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.
184 For more information, please see the ipcalc(1) man page.
186 int main(int argc, const char **argv) {
187 int showBroadcast = 0, showPrefix = 0, showNetwork = 0;
188 int showHostname = 0, showNetmask = 0;
192 char *ipStr, *prefixStr, *netmaskStr, *hostName, *chptr;
193 struct in_addr ip, netmask, network, broadcast;
196 struct poptOption optionsTable[] = {
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 " },
210 { NULL, '\0', 0, 0, 0, NULL, NULL }
213 optCon = poptGetContext("ipcalc", argc, argv, optionsTable, 0);
214 poptReadDefaultConfig(optCon, 1);
216 if ((rc = poptGetNextOpt(optCon)) < -1) {
218 fprintf(stderr, "ipcalc: bad argument %s: %s\n",
219 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
221 poptPrintHelp(optCon, stderr, 0);
226 if (!(ipStr = (char *) poptGetArg(optCon))) {
228 fprintf(stderr, "ipcalc: ip address expected\n");
229 poptPrintHelp(optCon, stderr, 0);
234 if (strchr(ipStr,'/') != NULL) {
235 prefixStr = strchr(ipStr, '/') + 1;
237 *prefixStr = '\0'; /* fix up ipStr */
242 if (prefixStr != NULL) {
243 prefix = atoi(prefixStr);
246 fprintf(stderr, "ipcalc: bad prefix: %s\n",
252 if (showBroadcast || showNetwork || showPrefix) {
253 if (!(netmaskStr = (char *) poptGetArg(optCon)) &&
256 fprintf(stderr, "ipcalc: netmask or prefix expected\n");
257 poptPrintHelp(optCon, stderr, 0);
260 } else if (netmaskStr && prefix != 0) {
262 fprintf(stderr, "ipcalc: both netmask and prefix specified\n");
263 poptPrintHelp(optCon, stderr, 0);
266 } else if (netmaskStr) {
267 if (!inet_aton(netmaskStr, &netmask)) {
269 fprintf(stderr, "ipcalc: bad netmask: %s\n",
273 prefix = mask2prefix(netmask.s_addr);
277 if ((chptr = (char *) poptGetArg(optCon))) {
279 fprintf(stderr, "ipcalc: unexpected argument: %s\n", chptr);
280 poptPrintHelp(optCon, stderr, 0);
285 /* Handle CIDR entries such as 172/8 */
290 for(i=3; i> 0; i--) {
291 tmp = strchr(tmp,'.');
299 tmp = malloc(strlen(ipStr) + 3);
300 sprintf(tmp,"%s.0",ipStr);
305 if (!inet_aton(ipStr, (struct in_addr *) &ip)) {
307 fprintf(stderr, "ipcalc: bad ip address: %s\n", ipStr);
312 if (!(showNetmask|showPrefix|showBroadcast|showNetwork|showHostname)) {
313 poptPrintHelp(optCon, stderr, 0);
317 poptFreeContext(optCon);
319 /* we know what we want to display now, so display it. */
323 netmask.s_addr = prefix2mask(prefix);
325 netmask.s_addr = default_netmask(ip.s_addr);
326 prefix = mask2prefix(netmask.s_addr);
329 printf("NETMASK=%s\n", inet_ntoa(netmask));
334 prefix = mask2prefix(ip.s_addr);
335 printf("PREFIX=%d\n", prefix);
339 broadcast.s_addr = calc_broadcast(ip.s_addr, prefix);
340 printf("BROADCAST=%s\n", inet_ntoa(broadcast));
344 network.s_addr = calc_network(ip.s_addr, prefix);
345 printf("NETWORK=%s\n", inet_ntoa(network));
349 if ((hostName = (char *) get_hostname(ip.s_addr)) == NULL) {
351 sprintf(errBuf, "ipcalc: cannot find hostname for %s", ipStr);
357 printf("HOSTNAME=%s\n", hostName);