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 | } |
---|