]> git.ipfire.org Git - thirdparty/dhcp.git/blame - common/inet.c
DHCPv6 branch merged to HEAD.
[thirdparty/dhcp.git] / common / inet.c
CommitLineData
089fb364
TL
1/* inet.c
2
3 Subroutines to manipulate internet addresses in a safely portable
4 way... */
5
6/*
98311e4b
DH
7 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1995-2003 by Internet Software Consortium
089fb364 9 *
98311e4b
DH
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
089fb364 13 *
98311e4b
DH
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
089fb364 21 *
98311e4b
DH
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * http://www.isc.org/
49733f31 27 *
98311e4b 28 * This software has been written for Internet Systems Consortium
49733f31 29 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
98311e4b 30 * To learn more about Internet Systems Consortium, see
49733f31
TL
31 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
32 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33 * ``http://www.nominum.com''.
089fb364
TL
34 */
35
341b9d40
TL
36#ifndef lint
37static char copyright[] =
98bd7ca0 38"$Id: inet.c,v 1.12 2007/05/08 23:05:20 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
341b9d40
TL
39#endif /* not lint */
40
089fb364
TL
41#include "dhcpd.h"
42
43/* Return just the network number of an internet address... */
44
45struct iaddr subnet_number (addr, mask)
46 struct iaddr addr;
47 struct iaddr mask;
48{
49 int i;
50 struct iaddr rv;
51
98311e4b
DH
52 if (addr.len > sizeof(addr.iabuf))
53 log_fatal("subnet_number():%s:%d: Invalid addr length.", MDL);
54 if (addr.len != mask.len)
55 log_fatal("subnet_number():%s:%d: Addr/mask length mismatch.",
56 MDL);
57
089fb364
TL
58 rv.len = 0;
59
60 /* Both addresses must have the same length... */
61 if (addr.len != mask.len)
62 return rv;
63
64 rv.len = addr.len;
65 for (i = 0; i < rv.len; i++)
66 rv.iabuf [i] = addr.iabuf [i] & mask.iabuf [i];
67 return rv;
68}
69
70/* Combine a network number and a integer to produce an internet address.
71 This won't work for subnets with more than 32 bits of host address, but
72 maybe this isn't a problem. */
73
74struct iaddr ip_addr (subnet, mask, host_address)
75 struct iaddr subnet;
76 struct iaddr mask;
73fd5718 77 u_int32_t host_address;
089fb364
TL
78{
79 int i, j, k;
73fd5718 80 u_int32_t swaddr;
089fb364
TL
81 struct iaddr rv;
82 unsigned char habuf [sizeof swaddr];
83
98311e4b
DH
84 if (subnet.len > sizeof(subnet.iabuf))
85 log_fatal("ip_addr():%s:%d: Invalid addr length.", MDL);
86 if (subnet.len != mask.len)
87 log_fatal("ip_addr():%s:%d: Addr/mask length mismatch.",
88 MDL);
89
089fb364
TL
90 swaddr = htonl (host_address);
91 memcpy (habuf, &swaddr, sizeof swaddr);
92
93 /* Combine the subnet address and the host address. If
94 the host address is bigger than can fit in the subnet,
95 return a zero-length iaddr structure. */
96 rv = subnet;
97 j = rv.len - sizeof habuf;
98 for (i = sizeof habuf - 1; i >= 0; i--) {
99 if (mask.iabuf [i + j]) {
97ca1699 100 if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) {
089fb364
TL
101 rv.len = 0;
102 return rv;
103 }
104 for (k = i - 1; k >= 0; k--) {
105 if (habuf [k]) {
106 rv.len = 0;
107 return rv;
108 }
109 }
97ca1699 110 rv.iabuf [i + j] |= habuf [i];
089fb364 111 break;
97ca1699
TL
112 } else
113 rv.iabuf [i + j] = habuf [i];
089fb364
TL
114 }
115
116 return rv;
117}
118
a3b267e9
TL
119/* Given a subnet number and netmask, return the address on that subnet
120 for which the host portion of the address is all ones (the standard
121 broadcast address). */
122
123struct iaddr broadcast_addr (subnet, mask)
124 struct iaddr subnet;
125 struct iaddr mask;
126{
127 int i, j, k;
128 struct iaddr rv;
129
98311e4b
DH
130 if (subnet.len > sizeof(subnet.iabuf))
131 log_fatal("broadcast_addr():%s:%d: Invalid addr length.", MDL);
132 if (subnet.len != mask.len)
133 log_fatal("broadcast_addr():%s:%d: Addr/mask length mismatch.",
134 MDL);
135
a3b267e9
TL
136 if (subnet.len != mask.len) {
137 rv.len = 0;
138 return rv;
139 }
140
141 for (i = 0; i < subnet.len; i++) {
142 rv.iabuf [i] = subnet.iabuf [i] | (~mask.iabuf [i] & 255);
143 }
144 rv.len = subnet.len;
145
146 return rv;
147}
148
73fd5718 149u_int32_t host_addr (addr, mask)
089fb364
TL
150 struct iaddr addr;
151 struct iaddr mask;
152{
153 int i;
73fd5718 154 u_int32_t swaddr;
089fb364
TL
155 struct iaddr rv;
156
98311e4b
DH
157 if (addr.len > sizeof(addr.iabuf))
158 log_fatal("host_addr():%s:%d: Invalid addr length.", MDL);
159 if (addr.len != mask.len)
160 log_fatal("host_addr():%s:%d: Addr/mask length mismatch.",
161 MDL);
162
089fb364
TL
163 rv.len = 0;
164
165 /* Mask out the network bits... */
166 rv.len = addr.len;
167 for (i = 0; i < rv.len; i++)
168 rv.iabuf [i] = addr.iabuf [i] & ~mask.iabuf [i];
169
170 /* Copy out up to 32 bits... */
171 memcpy (&swaddr, &rv.iabuf [rv.len - sizeof swaddr], sizeof swaddr);
172
173 /* Swap it and return it. */
174 return ntohl (swaddr);
175}
176
177int addr_eq (addr1, addr2)
178 struct iaddr addr1, addr2;
179{
98311e4b
DH
180 if (addr1.len > sizeof(addr1.iabuf))
181 log_fatal("addr_eq():%s:%d: Invalid addr length.", MDL);
182
089fb364
TL
183 if (addr1.len != addr2.len)
184 return 0;
185 return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0;
186}
187
febbd402
DH
188/* addr_match
189 *
190 * compares an IP address against a network/mask combination
191 * by ANDing the IP with the mask and seeing whether the result
192 * matches the masked network value.
193 */
194int
195addr_match(addr, match)
196 struct iaddr *addr;
197 struct iaddrmatch *match;
198{
199 int i;
200
201 if (addr->len != match->addr.len)
202 return 0;
203
204 i = 0;
205 for (i = 0 ; i < addr->len ; i++) {
206 if ((addr->iabuf[i] & match->mask.iabuf[i]) !=
207 match->addr.iabuf[i])
208 return 0;
209 }
210 return 1;
211}
212
98bd7ca0
DH
213/*
214 * Compares the addresses a1 and a2.
215 *
216 * If a1 < a2, returns -1.
217 * If a1 == a2, returns 0.
218 * If a1 > a2, returns 1.
219 *
220 * WARNING: if a1 and a2 differ in length, returns 0.
221 */
222int
223addr_cmp(const struct iaddr *a1, const struct iaddr *a2) {
089fb364
TL
224 int i;
225
98bd7ca0
DH
226 if (a1->len != a2->len) {
227 return 0;
228 }
229
230 for (i=0; i<a1->len; i++) {
231 if (a1->iabuf[i] < a2->iabuf[i]) {
232 return -1;
233 }
234 if (a1->iabuf[i] > a2->iabuf[i]) {
235 return 1;
236 }
237 }
238
239 return 0;
240}
241
242/*
243 * Performs a bitwise-OR of two addresses.
244 *
245 * Returns 1 if the result is non-zero, or 0 otherwise.
246 *
247 * WARNING: if a1 and a2 differ in length, returns 0.
248 */
249int
250addr_or(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
251 int i;
252 int all_zero;
253
254 if (a1->len != a2->len) {
255 return 0;
256 }
257
258 all_zero = 1;
259
260 result->len = a1->len;
261 for (i=0; i<a1->len; i++) {
262 result->iabuf[i] = a1->iabuf[i] | a2->iabuf[i];
263 if (result->iabuf[i] != 0) {
264 all_zero = 0;
265 }
266 }
267
268 return !all_zero;
269}
270
271/*
272 * Performs a bitwise-AND of two addresses.
273 *
274 * Returns 1 if the result is non-zero, or 0 otherwise.
275 *
276 * WARNING: if a1 and a2 differ in length, returns 0.
277 */
278int
279addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
280 int i;
281 int all_zero;
282
283 if (a1->len != a2->len) {
284 return 0;
285 }
286
287 all_zero = 1;
288
289 result->len = a1->len;
290 for (i=0; i<a1->len; i++) {
291 result->iabuf[i] = a1->iabuf[i] & a2->iabuf[i];
292 if (result->iabuf[i] != 0) {
293 all_zero = 0;
294 }
295 }
296
297 return !all_zero;
298}
299
300/*
301 * range2cidr
302 *
303 * Converts a range of IP addresses to a set of CIDR networks.
304 *
305 * Examples:
306 * 192.168.0.0 - 192.168.0.255 = 192.168.0.0/24
307 * 10.0.0.0 - 10.0.1.127 = 10.0.0.0/24, 10.0.1.0/25
308 * 255.255.255.32 - 255.255.255.255 = 255.255.255.32/27, 255.255.255.64/26,
309 * 255.255.255.128/25
310 */
311isc_result_t
312range2cidr(struct iaddrcidrnetlist **result,
313 const struct iaddr *lo, const struct iaddr *hi) {
314 struct iaddr addr;
315 struct iaddr mask;
316 int bit;
317 struct iaddr end_addr;
318 struct iaddr dummy;
319 int ofs, val;
320 struct iaddrcidrnetlist *net;
321 int tmp;
322
323 if (result == NULL) {
324 return ISC_R_INVALIDARG;
325 }
326 if (*result != NULL) {
327 return ISC_R_INVALIDARG;
328 }
329 if ((lo == NULL) || (hi == NULL) || (lo->len != hi->len)) {
330 return ISC_R_INVALIDARG;
331 }
332
333 /*
334 * Put our start and end in the right order, if reversed.
335 */
336 if (addr_cmp(lo, hi) > 0) {
337 const struct iaddr *tmp;
338 tmp = lo;
339 lo = hi;
340 hi = tmp;
341 }
342
343 /*
344 * Theory of operation:
345 *
346 * -------------------
347 * Start at the low end, and keep trying larger networks
348 * until we get one that is too big (explained below).
349 *
350 * We keep a "mask", which is the ones-complement of a
351 * normal netmask. So, a /23 has a netmask of 255.255.254.0,
352 * and a mask of 0.0.1.255.
353 *
354 * We know when a network is too big when we bitwise-AND the
355 * mask with the starting address and we get a non-zero
356 * result, like this:
357 *
358 * addr: 192.168.1.0, mask: 0.0.1.255
359 * bitwise-AND: 0.0.1.0
360 *
361 * A network is also too big if the bitwise-OR of the mask
362 * with the starting address is larger than the end address,
363 * like this:
364 *
365 * start: 192.168.1.0, mask: 0.0.1.255, end: 192.168.0.255
366 * bitwise-OR: 192.168.1.255
367 *
368 * -------------------
369 * Once we have found a network that is too big, we add the
370 * appropriate CIDR network to our list of found networks.
371 *
372 * We then use the next IP address as our low address, and
373 * begin the process of searching for a network that is
374 * too big again, starting with an empty mask.
375 */
376 addr = *lo;
377 bit = 0;
378 memset(&mask, 0, sizeof(mask));
379 mask.len = addr.len;
380 while (addr_cmp(&addr, hi) <= 0) {
381 /*
382 * Bitwise-OR mask with (1 << bit)
383 */
384 ofs = addr.len - (bit / 8) - 1;
385 val = 1 << (bit % 8);
386 if (ofs >= 0) {
387 mask.iabuf[ofs] |= val;
388 }
389
390 /*
391 * See if we're too big, and save this network if so.
392 */
393 addr_or(&end_addr, &addr, &mask);
394 if ((ofs < 0) ||
395 (addr_cmp(&end_addr, hi) > 0) ||
396 addr_and(&dummy, &addr, &mask)) {
397 /*
398 * Add a new prefix to our list.
399 */
400 net = dmalloc(sizeof(*net), MDL);
401 if (net == NULL) {
402 while (*result != NULL) {
403 net = (*result)->next;
404 dfree(*result, MDL);
405 *result = net;
406 }
407 return ISC_R_NOMEMORY;
408 }
409 net->cidrnet.lo_addr = addr;
410 net->cidrnet.bits = (addr.len * 8) - bit;
411 net->next = *result;
412 *result = net;
413
414 /*
415 * Figure out our new starting address,
416 * by adding (1 << bit) to our previous
417 * starting address.
418 */
419 tmp = addr.iabuf[ofs] + val;
420 while ((ofs >= 0) && (tmp > 255)) {
421 addr.iabuf[ofs] = tmp - 256;
422 ofs--;
423 tmp = addr.iabuf[ofs] + 1;
424 }
425 if (ofs < 0) {
426 /* Gone past last address, we're done. */
427 break;
428 }
429 addr.iabuf[ofs] = tmp;
430
431 /*
432 * Reset our bit and mask.
433 */
434 bit = 0;
435 memset(mask.iabuf, 0, sizeof(mask.iabuf));
436 memset(end_addr.iabuf, 0, sizeof(end_addr.iabuf));
437 } else {
438 /*
439 * If we're not too big, increase our network size.
440 */
441 bit++;
442 }
443 }
444
445 /*
446 * We're done.
447 */
448 return ISC_R_SUCCESS;
449}
450
451/*
452 * Free a list of CIDR networks, such as returned from range2cidr().
453 */
454isc_result_t
455free_iaddrcidrnetlist(struct iaddrcidrnetlist **result) {
456 struct iaddrcidrnetlist *p;
457
458 if (result == NULL) {
459 return ISC_R_INVALIDARG;
460 }
461 if (*result == NULL) {
462 return ISC_R_INVALIDARG;
463 }
464
465 while (*result != NULL) {
466 p = *result;
467 *result = p->next;
468 dfree(p, MDL);
469 }
470
471 return ISC_R_SUCCESS;
472}
473
474/* piaddr() turns an iaddr structure into a printable address. */
475/* XXX: should use a const pointer rather than passing the structure */
476const char *
477piaddr(const struct iaddr addr) {
478 static char
479 pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
480 /* "255.255.255.255" */
481
482 /* INSIST((addr.len == 0) || (addr.len == 4) || (addr.len == 16)); */
d758ad8c
TL
483
484 if (addr.len == 0) {
98bd7ca0 485 return "<null address>";
d758ad8c 486 }
98bd7ca0
DH
487 if (addr.len == 4) {
488 return inet_ntop(AF_INET, addr.iabuf, pbuf, sizeof(pbuf));
489 }
490 if (addr.len == 16) {
491 return inet_ntop(AF_INET6, addr.iabuf, pbuf, sizeof(pbuf));
d758ad8c 492 }
98bd7ca0
DH
493
494 log_fatal("piaddr():%s:%d: Invalid address length %d.", MDL,
495 addr.len);
496 /* quell compiler warnings */
497 return NULL;
d758ad8c
TL
498}
499
98bd7ca0
DH
500/* piaddrmask takes an iaddr structure mask, determines the bitlength of
501 * the mask, and then returns the printable CIDR notation of the two.
502 */
503char *
504piaddrmask(struct iaddr *addr, struct iaddr *mask) {
98311e4b 505 int mw;
98bd7ca0 506 unsigned int oct, bit;
98311e4b 507
98bd7ca0 508 if ((addr->len != 4) && (addr->len != 16))
98311e4b 509 log_fatal("piaddrmask():%s:%d: Address length %d invalid",
98bd7ca0
DH
510 MDL, addr->len);
511 if (addr->len != mask->len)
98311e4b
DH
512 log_fatal("piaddrmask():%s:%d: Address and mask size mismatch",
513 MDL);
514
515 /* Determine netmask width in bits. */
98bd7ca0 516 for (mw = (mask->len * 8) ; mw > 0 ; ) {
98311e4b
DH
517 oct = (mw - 1) / 8;
518 bit = 0x80 >> ((mw - 1) % 8);
98bd7ca0 519 if (!mask->iabuf[oct])
98311e4b 520 mw -= 8;
98bd7ca0 521 else if (mask->iabuf[oct] & bit)
d758ad8c 522 break;
d758ad8c 523 else
98311e4b 524 mw--;
d758ad8c 525 }
98311e4b 526
98bd7ca0
DH
527 if (mw < 0)
528 log_fatal("Impossible condition at %s:%d.", MDL);
529
530 return piaddrcidr(addr, mw);
531}
532
533/* Format an address and mask-length into printable CIDR notation. */
534char *
535piaddrcidr(const struct iaddr *addr, unsigned int bits) {
536 static char
537 ret[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128")];
538 /* "255.255.255.255/32" */
539
540 /* INSIST(addr != NULL); */
541 /* INSIST((addr->len == 4) || (addr->len == 16)); */
542 /* INSIST(bits <= (addr->len * 8)); */
543
544 if (bits > (addr->len * 8))
545 return NULL;
546
547 sprintf(ret, "%s/%d", piaddr(*addr), bits);
98311e4b 548
98bd7ca0 549 return ret;
d758ad8c
TL
550}
551