From ef25029f73c9e4c05797fbd6ba7779ed5185c107 Mon Sep 17 00:00:00 2001 From: Preston Brown Date: Mon, 30 Apr 2001 20:57:29 +0000 Subject: understands CIDR prefixes, operates more cleanly. --- src/ipcalc.1 | 40 ++++++-- src/ipcalc.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 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 +.nf +Preston Brown .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 + * Preston Brown #include #include +#include +#include #include #include #include #include -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; } -- cgit v1.2.1