3 Subroutines to manipulate internet addresses and ports in a safely portable
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
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.
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.
24 * Internet Systems Consortium, Inc.
26 * Redwood City, CA 94063
28 * https://www.isc.org/
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''.
40 /* Return just the network number of an internet address... */
42 struct iaddr subnet_number (addr, mask)
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.",
57 /* Both addresses must have the same length... */
58 if (addr.len != mask.len)
62 for (i = 0; i < rv.len; i++)
63 rv.iabuf [i] = addr.iabuf [i] & mask.iabuf [i];
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. */
71 struct iaddr ip_addr (subnet, mask, host_address)
74 u_int32_t host_address;
79 unsigned char habuf [sizeof swaddr];
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.",
87 swaddr = htonl (host_address);
88 memcpy (habuf, &swaddr, sizeof swaddr);
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. */
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)) {
101 for (k = i - 1; k >= 0; k--) {
107 rv.iabuf [i + j] |= habuf [i];
110 rv.iabuf [i + j] = habuf [i];
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). */
120 struct iaddr broadcast_addr (subnet, mask)
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.",
133 if (subnet.len != mask.len) {
138 for (i = 0; i < subnet.len; i++) {
139 rv.iabuf [i] = subnet.iabuf [i] | (~mask.iabuf [i] & 255);
146 u_int32_t host_addr (addr, mask)
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.",
162 /* Mask out the network bits... */
164 for (i = 0; i < rv.len; i++)
165 rv.iabuf [i] = addr.iabuf [i] & ~mask.iabuf [i];
167 /* Copy out up to 32 bits... */
168 memcpy (&swaddr, &rv.iabuf [rv.len - sizeof swaddr], sizeof swaddr);
170 /* Swap it and return it. */
171 return ntohl (swaddr);
174 int addr_eq (addr1, addr2)
175 struct iaddr addr1, addr2;
177 if (addr1.len > sizeof(addr1.iabuf))
178 log_fatal("addr_eq():%s:%d: Invalid addr length.", MDL);
180 if (addr1.len != addr2.len)
182 return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0;
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.
192 addr_match(addr, match)
194 struct iaddrmatch *match;
198 if (addr->len != match->addr.len)
202 for (i = 0 ; i < addr->len ; i++) {
203 if ((addr->iabuf[i] & match->mask.iabuf[i]) !=
204 match->addr.iabuf[i])
211 * Compares the addresses a1 and a2.
213 * If a1 < a2, returns -1.
214 * If a1 == a2, returns 0.
215 * If a1 > a2, returns 1.
217 * WARNING: if a1 and a2 differ in length, returns 0.
220 addr_cmp(const struct iaddr *a1, const struct iaddr *a2) {
223 if (a1->len != a2->len) {
227 for (i=0; i<a1->len; i++) {
228 if (a1->iabuf[i] < a2->iabuf[i]) {
231 if (a1->iabuf[i] > a2->iabuf[i]) {
240 * Performs a bitwise-OR of two addresses.
242 * Returns 1 if the result is non-zero, or 0 otherwise.
244 * WARNING: if a1 and a2 differ in length, returns 0.
247 addr_or(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
251 if (a1->len != a2->len) {
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) {
269 * Performs a bitwise-AND of two addresses.
271 * Returns 1 if the result is non-zero, or 0 otherwise.
273 * WARNING: if a1 and a2 differ in length, returns 0.
276 addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
280 if (a1->len != a2->len) {
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) {
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.
309 * Because the final ".1" would get masked out by the /8.
312 is_cidr_mask_valid(const struct iaddr *addr, int bits) {
320 * Check our bit boundaries.
325 if (bits > (addr->len * 8)) {
330 * Figure out how many low-order bits need to be zero.
332 zero_bits = (addr->len * 8) - bits;
333 zero_bytes = zero_bits / 8;
336 * Check to make sure the low-order bytes are zero.
338 for (i=1; i<=zero_bytes; i++) {
339 if (addr->iabuf[addr->len-i] != 0) {
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
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);
360 * Converts a range of IP addresses to a set of CIDR networks.
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,
369 range2cidr(struct iaddrcidrnetlist **result,
370 const struct iaddr *lo, const struct iaddr *hi) {
374 struct iaddr end_addr;
377 struct iaddrcidrnetlist *net;
380 if (result == NULL) {
381 return DHCP_R_INVALIDARG;
383 if (*result != NULL) {
384 return DHCP_R_INVALIDARG;
386 if ((lo == NULL) || (hi == NULL) || (lo->len != hi->len)) {
387 return DHCP_R_INVALIDARG;
391 * Put our start and end in the right order, if reversed.
393 if (addr_cmp(lo, hi) > 0) {
394 const struct iaddr *tmp;
401 * Theory of operation:
403 * -------------------
404 * Start at the low end, and keep trying larger networks
405 * until we get one that is too big (explained below).
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.
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
415 * addr: 192.168.1.0, mask: 0.0.1.255
416 * bitwise-AND: 0.0.1.0
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,
422 * start: 192.168.1.0, mask: 0.0.1.255, end: 192.168.0.255
423 * bitwise-OR: 192.168.1.255
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.
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.
435 memset(&mask, 0, sizeof(mask));
437 while (addr_cmp(&addr, hi) <= 0) {
439 * Bitwise-OR mask with (1 << bit)
441 ofs = addr.len - (bit / 8) - 1;
442 val = 1 << (bit % 8);
444 mask.iabuf[ofs] |= val;
448 * See if we're too big, and save this network if so.
450 addr_or(&end_addr, &addr, &mask);
452 (addr_cmp(&end_addr, hi) > 0) ||
453 addr_and(&dummy, &addr, &mask)) {
455 * Add a new prefix to our list.
457 net = dmalloc(sizeof(*net), MDL);
459 while (*result != NULL) {
460 net = (*result)->next;
464 return ISC_R_NOMEMORY;
466 net->cidrnet.lo_addr = addr;
467 net->cidrnet.bits = (addr.len * 8) - bit;
472 * Figure out our new starting address,
473 * by adding (1 << bit) to our previous
476 tmp = addr.iabuf[ofs] + val;
477 while ((ofs >= 0) && (tmp > 255)) {
478 addr.iabuf[ofs] = tmp - 256;
480 tmp = addr.iabuf[ofs] + 1;
483 /* Gone past last address, we're done. */
486 addr.iabuf[ofs] = tmp;
489 * Reset our bit and mask.
492 memset(mask.iabuf, 0, sizeof(mask.iabuf));
493 memset(end_addr.iabuf, 0, sizeof(end_addr.iabuf));
496 * If we're not too big, increase our network size.
505 return ISC_R_SUCCESS;
509 * Free a list of CIDR networks, such as returned from range2cidr().
512 free_iaddrcidrnetlist(struct iaddrcidrnetlist **result) {
513 struct iaddrcidrnetlist *p;
515 if (result == NULL) {
516 return DHCP_R_INVALIDARG;
518 if (*result == NULL) {
519 return DHCP_R_INVALIDARG;
522 while (*result != NULL) {
528 return ISC_R_SUCCESS;
531 /* piaddr() turns an iaddr structure into a printable address. */
532 /* XXX: should use a const pointer rather than passing the structure */
534 piaddr(const struct iaddr addr) {
536 pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
537 /* "255.255.255.255" */
539 /* INSIST((addr.len == 0) || (addr.len == 4) || (addr.len == 16)); */
542 return "<null address>";
545 return inet_ntop(AF_INET, addr.iabuf, pbuf, sizeof(pbuf));
547 if (addr.len == 16) {
548 return inet_ntop(AF_INET6, addr.iabuf, pbuf, sizeof(pbuf));
551 log_fatal("piaddr():%s:%d: Invalid address length %d.", MDL,
553 /* quell compiler warnings */
557 /* piaddrmask takes an iaddr structure mask, determines the bitlength of
558 * the mask, and then returns the printable CIDR notation of the two.
561 piaddrmask(struct iaddr *addr, struct iaddr *mask) {
563 unsigned int oct, bit;
565 if ((addr->len != 4) && (addr->len != 16))
566 log_fatal("piaddrmask():%s:%d: Address length %d invalid",
568 if (addr->len != mask->len)
569 log_fatal("piaddrmask():%s:%d: Address and mask size mismatch",
572 /* Determine netmask width in bits. */
573 for (mw = (mask->len * 8) ; mw > 0 ; ) {
575 bit = 0x80 >> ((mw - 1) % 8);
576 if (!mask->iabuf[oct])
578 else if (mask->iabuf[oct] & bit)
585 log_fatal("Impossible condition at %s:%d.", MDL);
587 return piaddrcidr(addr, mw);
590 /* Format an address and mask-length into printable CIDR notation. */
592 piaddrcidr(const struct iaddr *addr, unsigned int bits) {
594 ret[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128")];
595 /* "255.255.255.255/32" */
597 /* INSIST(addr != NULL); */
598 /* INSIST((addr->len == 4) || (addr->len == 16)); */
599 /* INSIST(bits <= (addr->len * 8)); */
601 if (bits > (addr->len * 8))
604 sprintf(ret, "%s/%d", piaddr(*addr), bits);
609 /* Validate that the string represents a valid port number and
610 * return it in network byte order
614 validate_port(char *port) {
621 local_port = strtol(port, &endptr, 10);
623 if ((*endptr != '\0') || (errno == ERANGE) || (errno == EINVAL))
624 log_fatal ("Invalid port number specification: %s", port);
626 if (local_port < lower || local_port > upper)
627 log_fatal("Port number specified is out of range (%ld-%ld).",
630 return htons((u_int16_t)local_port);