aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPreston Brown <pbrown@redhat.com>2001-04-30 20:57:29 +0000
committerPreston Brown <pbrown@redhat.com>2001-04-30 20:57:29 +0000
commitef25029f73c9e4c05797fbd6ba7779ed5185c107 (patch)
tree244d7f214ddabdde603934b78e837cdb05b06c6a
parent4b0faa32f3ce02d731ddabf42759402fbee055e9 (diff)
downloadinitscripts-ef25029f73c9e4c05797fbd6ba7779ed5185c107.tar
initscripts-ef25029f73c9e4c05797fbd6ba7779ed5185c107.tar.gz
initscripts-ef25029f73c9e4c05797fbd6ba7779ed5185c107.tar.bz2
initscripts-ef25029f73c9e4c05797fbd6ba7779ed5185c107.tar.xz
initscripts-ef25029f73c9e4c05797fbd6ba7779ed5185c107.zip
understands CIDR prefixes, operates more cleanly.
-rw-r--r--src/ipcalc.140
-rw-r--r--src/ipcalc.c306
2 files changed, 286 insertions, 60 deletions
diff --git a/src/ipcalc.1 b/src/ipcalc.1
index c637eb4a..d5a3e39f 100644
--- a/src/ipcalc.1
+++ b/src/ipcalc.1
@@ -1,36 +1,56 @@
-.TH IPCALC 1 "Red Hat Software" "RHS" \" -*- nroff -*-
+.TH IPCALC 1 "April 30 2001" "Red Hat, Inc." RH \" -*- nroff -*-
.SH NAME
ipcalc \- perform simple manipulation of IP addresses
.SH SYNOPSIS
.B ipcalc
-\fI[--hostname] [--broadcast] [--network] [--netmask] \fBip \fI[netmask]\fR
+[\fIOPTION\fR]... <\fBIP address\fR>[\fI/prefix\fR] [\fInetmask\fR]
.SH DESCRIPTION
\fBipcalc\fR provides a simple way to calculate IP information for a host.
The various options specify what information \fBipcalc\fR should display
-on standard out. Multiple options may be specified.
+on standard out. Multiple options may be specified. An IP address to
+operate on must always be specified. Most operations also require a
+netmask or a CIDR prefix as well.
.SH OPTIONS
.TP
-.IP \fI--broadcast\fR
+.TP
+\fB\-b\fR, \fB\-\-broadcast\fR
Display the broadcast address for the given IP address and netmask.
-.IP \fI--hostname\fR
+.TP
+\fB\-h\fR, \fB\-\-hostname\fR
Display the hostname for the given IP address.
-.IP \fI--netmask\fR
+.TP
+\fB\-m\fR, \fB\-\-netmask\fR
Calculate the netmask for the given IP address. It assumes that the IP
-address is in a complete Class A, B, or C network. Many networks do
+address is in a complete class A, B, or C network. Many networks do
not use the default netmasks, in which case an inappropriate value will
be returned.
-.IP \fI--network\fR
+.TP
+\fB\-n\fR, \fB\-\-network\fR
Display the network address for the given IP address and netmask.
-.IP \fI--silent\fR
+.TP
+\fB\-s\fR, \fB\-\-silent\fR
Don't ever display error messages.
-.SH AUTHOR
+.SH AUTHORS
.nf
Erik Troan <ewt@redhat.com>
+.nf
+Preston Brown <pbrown@redhat.com>
.fi
+.SH "REPORTING BUGS"
+Report bugs to our bugtracking system:
+http://bugzilla.redhat.com/bugzilla.
+.SH COPYRIGHT
+Copyright \(co 1997-2001 Red Hat, Inc.
+.br
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE.
+.SH "SEE ALSO"
+ipcalc(3)
diff --git a/src/ipcalc.c b/src/ipcalc.c
index 922d2cc5..3fb2bcc6 100644
--- a/src/ipcalc.c
+++ b/src/ipcalc.c
@@ -1,121 +1,327 @@
+/*
+ * Copyright (c) 1997-2001 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors:
+ * Erik Troan <ewt@redhat.com>
+ * Preston Brown <pbrown@redhat.com
+ */
+
+
#include <ctype.h>
#include <popt.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
-typedef unsigned int int32;
+/*!
+ \def IPBITS
+ \brief the number of bits in an IP address.
+*/
+#define IPBITS (sizeof(unsigned long int) * 8)
+/*!
+ \def IPBYTES
+ \brief the number of bytes in an IP address.
+*/
+#define IPBYTES (sizeof(unsigned long int))
+
+
+/*!
+ \file ipcalc.c
+ \brief provides utilities for manipulating IP addresses.
+
+ ipcalc provides utilities and a front-end command line interface for
+ manipulating IP addresses, and calculating various aspects of an ip
+ address/netmask/network address/prefix/etc.
+
+ Functionality can be accessed from other languages from the library
+ interface, documented here. To use ipcalc from the shell, read the
+ ipcalc(1) manual page.
+
+ When passing parameters to the various functions, take note of whether they
+ take host byte order or network byte order. Most take host byte order, and
+ return host byte order, but there are some exceptions.
+
+*/
+
+/*!
+ \fn unsigned long int prefix2mask(int bits)
+ \brief creates a netmask from a specified number of bits
+
+ This function converts a prefix length to a netmask. As CIDR (classless
+ internet domain internet domain routing) has taken off, more an more IP
+ addresses are being specified in the format address/prefix
+ (i.e. 192.168.2.3/24, with a corresponding netmask 255.255.255.0). If you
+ need to see what netmask corresponds to the prefix part of the address, this
+ is the function. See also \ref mask2prefix.
+
+ \param prefix is the number of bits to create a mask for.
+ \return a network mask, in network byte order.
+*/
+unsigned long int prefix2mask(int prefix) {
+ return htonl(~((2 << (31 - prefix)) - 1));
+}
+
+/*!
+ \fn int mask2prefix(unsigned long int mask)
+ \brief calculates the number of bits masked off by a netmask.
+
+ This function calculates the significant bits in an IP address as specified by
+ a netmask. See also \ref prefix2mask.
+
+ \param mask is the netmask, specified as an unsigned long integer in network byte order.
+ \return the number of significant bits. */
+int mask2prefix(unsigned long int mask)
+{
+ int i;
+ int count = IPBITS;
+
+ for (i = 0; i < IPBITS; i++) {
+ if (!(ntohl(mask) & ((2 << i) - 1)))
+ count--;
+ }
+
+ return count;
+}
+
+/*!
+ \fn unsigned long int default_netmask(unsigned long int addr)
+
+ \brief returns the default (canonical) netmask associated with specified IP
+ address.
+
+ When the Internet was originally set up, various ranges of IP addresses were
+ segmented into three network classes: A, B, and C. This function will return
+ a netmask that is associated with the IP address specified defining where it
+ falls in the predefined classes.
+
+ \param addr an IP address in network byte order.
+ \return a netmask in network byte order. */
+unsigned long int default_netmask(unsigned long int addr)
+{
+ if (((ntohl(addr) & 0xFF000000) >> 24) <= 127)
+ return htonl(0xFF000000);
+ else if (((ntohl(addr) & 0xFF000000) >> 24) <= 191)
+ return htonl(0xFFFF0000);
+ else
+ return htonl(0xFFFFFF00);
+}
+
+/*!
+ \fn unsigned long int calc_broadcast(unsigned long int addr, int prefix)
+
+ \brief calculate broadcast address given an IP address and a prefix length.
+
+ \param addr an IP address in network byte order.
+ \param prefix a prefix length.
+
+ \return the calculated broadcast address for the network, in network byte
+ order.
+*/
+unsigned long int calc_broadcast(unsigned long int addr,
+ int prefix)
+{
+ return (addr & prefix2mask(prefix)) | ~prefix2mask(prefix);
+}
+
+/*!
+ \fn unsigned long int calc_network(unsigned long int addr, int prefix)
+ \brief calculates the network address for a specified address and prefix.
+
+ \param addr an IP address, in network byte order
+ \param prefix the network prefix
+ \return the base address of the network that addr is associated with, in
+ network byte order.
+*/
+unsigned long int calc_network(unsigned long int addr, int prefix)
+{
+ return (addr & prefix2mask(prefix));
+}
+
+/*!
+ \fn const char *get_hostname(unsigned long int addr)
+ \brief returns the hostname associated with the specified IP address
+
+ \param addr an IP address to find a hostname for, in network byte order
+
+ \return a hostname, or NULL if one cannot be determined. Hostname is stored
+ in a static buffer that may disappear at any time, the caller should copy the
+ data if it needs permanent storage.
+*/
+const char *get_hostname(unsigned long int addr)
+{
+ struct hostent * hostinfo;
+ int x;
+
+ hostinfo = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
+ if (!hostinfo)
+ return NULL;
+
+ for (x=0; hostinfo->h_name[x]; x++) {
+ hostinfo->h_name[x] = tolower(hostinfo->h_name[x]);
+ }
+ return hostinfo->h_name;
+}
-int main(int argc, char ** argv) {
+/*!
+ \fn main(int argc, const char **argv)
+ \brief wrapper program for ipcalc functions.
+
+ This is a wrapper program for the functions that the ipcalc library provides.
+ It can be used from shell scripts or directly from the command line.
+
+ For more information, please see the ipcalc(1) man page.
+*/
+int main(int argc, const char **argv) {
int showBroadcast = 0, showNetwork = 0, showHostname = 0, showNetmask = 0;
int beSilent = 0;
int rc;
poptContext optCon;
- char * ipStr, * netmaskStr, * chptr;
- int32 ip, netmask, network, broadcast;
- struct hostent * hostinfo;
+ char *ipStr, *prefixStr, *netmaskStr, *hostName, *chptr;
+ struct in_addr ip, netmask, network, broadcast;
+ int prefix = 0;
char errBuf[250];
struct poptOption optionsTable[] = {
- { "broadcast", '\0', 0, &showBroadcast, 0,
+ { "broadcast", 'b', 0, &showBroadcast, 0,
"Display calculated broadcast address", },
- { "hostname", '\0', 0, &showHostname, 0,
+ { "hostname", 'h', 0, &showHostname, 0,
"Show hostname determined via DNS" },
- { "netmask", '\0', 0, &showNetmask, 0,
+ { "netmask", 'm', 0, &showNetmask, 0,
"Display default netmask for IP (class A, B, or C)" },
- { "network", '\0', 0, &showNetwork, 0,
+ { "network", 'n', 0, &showNetwork, 0,
"Display calculated network address", },
- { "silent", '\0', 0, &beSilent, 0,
+ { "silent", 's', 0, &beSilent, 0,
"Don't ever display error messages " },
POPT_AUTOHELP
- { NULL, '\0', 0, 0, 0 },
+ POPT_TABLEEND
};
- optCon = poptGetContext("ipcalc", argc, argv, optionsTable,0);
+ optCon = poptGetContext("ipcalc", argc, argv, optionsTable, 0);
poptReadDefaultConfig(optCon, 1);
if ((rc = poptGetNextOpt(optCon)) < -1) {
- if (!beSilent)
+ if (!beSilent) {
fprintf(stderr, "ipcalc: bad argument %s: %s\n",
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
+ poptPrintHelp(optCon, stderr, 0);
+ }
return 1;
}
- if (!(ipStr = poptGetArg(optCon))) {
- if (!beSilent)
+ if (!(ipStr = (char *) poptGetArg(optCon))) {
+ if (!beSilent) {
fprintf(stderr, "ipcalc: ip address expected\n");
+ poptPrintHelp(optCon, stderr, 0);
+ }
return 1;
}
- if (showBroadcast || showNetwork) {
- if (!(netmaskStr = poptGetArg(optCon))) {
+ if (strchr(ipStr,'/') != NULL) {
+ prefixStr = strchr(ipStr, '/') + 1;
+ prefixStr--;
+ *prefixStr = '\0'; /* fix up ipStr */
+ prefixStr++;
+ } else
+ prefixStr = NULL;
+
+ if (!inet_aton(ipStr, &ip)) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad ip address: %s\n",
+ ipStr);
+ return 1;
+ }
+
+ if (prefixStr != NULL) {
+ prefix = atoi(prefixStr);
+ if (prefix == 0) {
if (!beSilent)
- fprintf(stderr, "ipcalc: netmask expected\n");
+ fprintf(stderr, "ipcalc: bad prefix: %s\n",
+ prefixStr);
return 1;
}
-
- if (!inet_aton(netmaskStr, (struct in_addr *) &netmask)) {
- if (!beSilent)
- fprintf(stderr, "ipcalc: bad netmask: %s\n", netmaskStr);
+ }
+
+ if (showBroadcast || showNetwork) {
+ if (!(netmaskStr = (char *) poptGetArg(optCon)) &&
+ (prefix == 0)) {
+ if (!beSilent) {
+ fprintf(stderr, "ipcalc: netmask or prefix expected\n");
+ poptPrintHelp(optCon, stderr, 0);
+ }
return 1;
+ } else if (netmaskStr) {
+ if (!inet_aton(netmaskStr, &netmask)) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad netmask: %s\n",
+ netmaskStr);
+ return 1;
+ }
+ prefix = mask2prefix(netmask.s_addr);
}
}
- if ((chptr = poptGetArg(optCon))) {
- if (!beSilent)
+ if ((chptr = (char *) poptGetArg(optCon))) {
+ if (!beSilent) {
fprintf(stderr, "ipcalc: unexpected argument: %s\n", chptr);
+ poptPrintHelp(optCon, stderr, 0);
+ }
return 1;
}
- poptFreeContext(optCon);
-
if (!inet_aton(ipStr, (struct in_addr *) &ip)) {
if (!beSilent)
fprintf(stderr, "ipcalc: bad ip address: %s\n", ipStr);
return 1;
}
+ poptFreeContext(optCon);
+
+ /* we know what we want to display now, so display it. */
+
if (showNetmask) {
- if (((ntohl(ip) & 0xFF000000) >> 24) <= 127)
- chptr = "255.0.0.0";
- else if (((ntohl(ip) & 0xFF000000) >> 24) <= 191)
- chptr = "255.255.0.0";
- else
- chptr = "255.255.255.0";
-
- printf("NETMASK=%s\n", chptr);
+ if (prefix) {
+ netmask.s_addr = prefix2mask(prefix);
+ } else {
+ netmask.s_addr = default_netmask(ip.s_addr);
+ prefix = mask2prefix(netmask.s_addr);
+ }
+
+ printf("PREFIX=%d\n", prefix);
+ printf("NETMASK=%s\n", inet_ntoa(netmask));
}
if (showBroadcast) {
- broadcast = (ip & netmask) | ~netmask;
- printf("BROADCAST=%s\n", inet_ntoa(*((struct in_addr *) &broadcast)));
+ broadcast.s_addr = calc_broadcast(ip.s_addr, prefix);
+ printf("BROADCAST=%s\n", inet_ntoa(broadcast));
}
if (showNetwork) {
- network = ip & netmask;
- printf("NETWORK=%s\n", inet_ntoa(*((struct in_addr *) &network)));
+ network.s_addr = calc_network(ip.s_addr, prefix);
+ printf("NETWORK=%s\n", inet_ntoa(network));
}
-
- if (showHostname) {
- int x;
- hostinfo = gethostbyaddr((char *) &ip, sizeof(ip), AF_INET);
- if (!hostinfo) {
+
+ if (showHostname) {
+ if ((hostName = (char *) get_hostname(ip.s_addr)) == NULL) {
if (!beSilent) {
sprintf(errBuf, "ipcalc: cannot find hostname for %s", ipStr);
herror(errBuf);
}
-
return 1;
}
- for (x=0; hostinfo->h_name[x]; x++) {
- hostinfo->h_name[x] = tolower(hostinfo->h_name[x]);
- }
-
- printf("HOSTNAME=%s\n", hostinfo->h_name);
+
+ printf("HOSTNAME=%s\n", hostName);
}
-
return 0;
}