[1108] | 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 | */ |
---|
| 78 | u_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. */ |
---|
| 91 | int 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. */ |
---|
| 117 | u_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 | */ |
---|
| 138 | u_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 | */ |
---|
| 153 | u_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 | */ |
---|
| 168 | const 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 | */ |
---|
| 192 | int 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 | } |
---|