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