common/inet.c

Go to the documentation of this file.
00001 /* inet.c
00002 
00003    Subroutines to manipulate internet addresses and ports in a safely portable
00004    way... */
00005 
00006 /*
00007  * Copyright (c) 2011,2013,2014 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 2007-2009 by Internet Systems Consortium, Inc. ("ISC")
00009  * Copyright (c) 2004,2005 by Internet Systems Consortium, Inc. ("ISC")
00010  * Copyright (c) 1995-2003 by Internet Software Consortium
00011  *
00012  * Permission to use, copy, modify, and distribute this software for any
00013  * purpose with or without fee is hereby granted, provided that the above
00014  * copyright notice and this permission notice appear in all copies.
00015  *
00016  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00017  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00018  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00019  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00020  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00021  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00022  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00023  *
00024  *   Internet Systems Consortium, Inc.
00025  *   950 Charter Street
00026  *   Redwood City, CA 94063
00027  *   <info@isc.org>
00028  *   https://www.isc.org/
00029  *
00030  */
00031 
00032 #include "dhcpd.h"
00033 
00034 /* Return just the network number of an internet address... */
00035 
00036 struct iaddr subnet_number (addr, mask)
00037         struct iaddr addr;
00038         struct iaddr mask;
00039 {
00040         int i;
00041         struct iaddr rv;
00042 
00043         if (addr.len > sizeof(addr.iabuf))
00044                 log_fatal("subnet_number():%s:%d: Invalid addr length.", MDL);
00045         if (addr.len != mask.len)
00046                 log_fatal("subnet_number():%s:%d: Addr/mask length mismatch.",
00047                           MDL);
00048 
00049         rv.len = 0;
00050 
00051         /* Both addresses must have the same length... */
00052         if (addr.len != mask.len)
00053                 return rv;
00054 
00055         rv.len = addr.len;
00056         for (i = 0; i < rv.len; i++)
00057                 rv.iabuf [i] = addr.iabuf [i] & mask.iabuf [i];
00058         return rv;
00059 }
00060 
00061 /* Combine a network number and a integer to produce an internet address.
00062    This won't work for subnets with more than 32 bits of host address, but
00063    maybe this isn't a problem. */
00064 
00065 struct iaddr ip_addr (subnet, mask, host_address)
00066         struct iaddr subnet;
00067         struct iaddr mask;
00068         u_int32_t host_address;
00069 {
00070         int i, j, k;
00071         u_int32_t swaddr;
00072         struct iaddr rv;
00073         unsigned char habuf [sizeof swaddr];
00074 
00075         if (subnet.len > sizeof(subnet.iabuf))
00076                 log_fatal("ip_addr():%s:%d: Invalid addr length.", MDL);
00077         if (subnet.len != mask.len)
00078                 log_fatal("ip_addr():%s:%d: Addr/mask length mismatch.",
00079                           MDL);
00080 
00081         swaddr = htonl (host_address);
00082         memcpy (habuf, &swaddr, sizeof swaddr);
00083 
00084         /* Combine the subnet address and the host address.   If
00085            the host address is bigger than can fit in the subnet,
00086            return a zero-length iaddr structure. */
00087         rv = subnet;
00088         j = rv.len - sizeof habuf;
00089         for (i = sizeof habuf - 1; i >= 0; i--) {
00090                 if (mask.iabuf [i + j]) {
00091                         if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) {
00092                                 rv.len = 0;
00093                                 return rv;
00094                         }
00095                         for (k = i - 1; k >= 0; k--) {
00096                                 if (habuf [k]) {
00097                                         rv.len = 0;
00098                                         return rv;
00099                                 }
00100                         }
00101                         rv.iabuf [i + j] |= habuf [i];
00102                         break;
00103                 } else
00104                         rv.iabuf [i + j] = habuf [i];
00105         }
00106                 
00107         return rv;
00108 }
00109 
00110 /* Given a subnet number and netmask, return the address on that subnet
00111    for which the host portion of the address is all ones (the standard
00112    broadcast address). */
00113 
00114 struct iaddr broadcast_addr (subnet, mask)
00115         struct iaddr subnet;
00116         struct iaddr mask;
00117 {
00118         int i;
00119         struct iaddr rv;
00120 
00121         if (subnet.len > sizeof(subnet.iabuf))
00122                 log_fatal("broadcast_addr():%s:%d: Invalid addr length.", MDL);
00123         if (subnet.len != mask.len)
00124                 log_fatal("broadcast_addr():%s:%d: Addr/mask length mismatch.",
00125                           MDL);
00126 
00127         if (subnet.len != mask.len) {
00128                 rv.len = 0;
00129                 return rv;
00130         }
00131 
00132         for (i = 0; i < subnet.len; i++) {
00133                 rv.iabuf [i] = subnet.iabuf [i] | (~mask.iabuf [i] & 255);
00134         }
00135         rv.len = subnet.len;
00136 
00137         return rv;
00138 }
00139 
00140 u_int32_t host_addr (addr, mask)
00141         struct iaddr addr;
00142         struct iaddr mask;
00143 {
00144         int i;
00145         u_int32_t swaddr;
00146         struct iaddr rv;
00147 
00148         if (addr.len > sizeof(addr.iabuf))
00149                 log_fatal("host_addr():%s:%d: Invalid addr length.", MDL);
00150         if (addr.len != mask.len)
00151                 log_fatal("host_addr():%s:%d: Addr/mask length mismatch.",
00152                           MDL);
00153 
00154         rv.len = 0;
00155 
00156         /* Mask out the network bits... */
00157         rv.len = addr.len;
00158         for (i = 0; i < rv.len; i++)
00159                 rv.iabuf [i] = addr.iabuf [i] & ~mask.iabuf [i];
00160 
00161         /* Copy out up to 32 bits... */
00162         memcpy (&swaddr, &rv.iabuf [rv.len - sizeof swaddr], sizeof swaddr);
00163 
00164         /* Swap it and return it. */
00165         return ntohl (swaddr);
00166 }
00167 
00168 int addr_eq (addr1, addr2)
00169         struct iaddr addr1, addr2;
00170 {
00171         if (addr1.len > sizeof(addr1.iabuf))
00172                 log_fatal("addr_eq():%s:%d: Invalid addr length.", MDL);
00173 
00174         if (addr1.len != addr2.len)
00175                 return 0;
00176         return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0;
00177 }
00178 
00179 /* addr_match 
00180  *
00181  * compares an IP address against a network/mask combination
00182  * by ANDing the IP with the mask and seeing whether the result
00183  * matches the masked network value.
00184  */
00185 int
00186 addr_match(addr, match)
00187         struct iaddr *addr;
00188         struct iaddrmatch *match;
00189 {
00190         int i;
00191 
00192         if (addr->len != match->addr.len)
00193                 return 0;
00194         
00195         for (i = 0 ; i < addr->len ; i++) {
00196                 if ((addr->iabuf[i] & match->mask.iabuf[i]) !=
00197                                                         match->addr.iabuf[i])
00198                         return 0;
00199         }
00200         return 1;
00201 }
00202 
00203 /* 
00204  * Compares the addresses a1 and a2.
00205  *
00206  * If a1 < a2, returns -1.
00207  * If a1 == a2, returns 0.
00208  * If a1 > a2, returns 1.
00209  *
00210  * WARNING: if a1 and a2 differ in length, returns 0.
00211  */
00212 int
00213 addr_cmp(const struct iaddr *a1, const struct iaddr *a2) {
00214         int i;
00215 
00216         if (a1->len != a2->len) {
00217                 return 0;
00218         }
00219 
00220         for (i=0; i<a1->len; i++) {
00221                 if (a1->iabuf[i] < a2->iabuf[i]) {
00222                         return -1;
00223                 }
00224                 if (a1->iabuf[i] > a2->iabuf[i]) {
00225                         return 1;
00226                 }
00227         }
00228 
00229         return 0;
00230 }
00231 
00232 /*
00233  * Performs a bitwise-OR of two addresses.
00234  *
00235  * Returns 1 if the result is non-zero, or 0 otherwise.
00236  *
00237  * WARNING: if a1 and a2 differ in length, returns 0.
00238  */
00239 int 
00240 addr_or(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
00241         int i;
00242         int all_zero;
00243 
00244         if (a1->len != a2->len) {
00245                 return 0;
00246         }
00247 
00248         all_zero = 1;
00249 
00250         result->len = a1->len;
00251         for (i=0; i<a1->len; i++) {
00252                 result->iabuf[i] = a1->iabuf[i] | a2->iabuf[i];
00253                 if (result->iabuf[i] != 0) {
00254                         all_zero = 0;
00255                 }
00256         }
00257 
00258         return !all_zero;
00259 }
00260 
00261 /*
00262  * Performs a bitwise-AND of two addresses.
00263  *
00264  * Returns 1 if the result is non-zero, or 0 otherwise.
00265  *
00266  * WARNING: if a1 and a2 differ in length, returns 0.
00267  */
00268 int 
00269 addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
00270         int i;
00271         int all_zero;
00272 
00273         if (a1->len != a2->len) {
00274                 return 0;
00275         }
00276 
00277         all_zero = 1;
00278 
00279         result->len = a1->len;
00280         for (i=0; i<a1->len; i++) {
00281                 result->iabuf[i] = a1->iabuf[i] & a2->iabuf[i];
00282                 if (result->iabuf[i] != 0) {
00283                         all_zero = 0;
00284                 }
00285         }
00286 
00287         return !all_zero;
00288 }
00289 
00290 /*
00291  * Check if a bitmask of the given length is valid for the address.
00292  * This is not the case if any bits longer than the bitmask are 1.
00293  *
00294  * So, this is valid:
00295  *
00296  * 127.0.0.0/8
00297  *
00298  * But this is not:
00299  *
00300  * 127.0.0.1/8
00301  *
00302  * Because the final ".1" would get masked out by the /8.
00303  */
00304 isc_boolean_t
00305 is_cidr_mask_valid(const struct iaddr *addr, int bits) {
00306         int zero_bits;
00307         int zero_bytes;
00308         int i;
00309         char byte;
00310         int shift_bits;
00311 
00312         /*
00313          * Check our bit boundaries.
00314          */
00315         if (bits < 0) {
00316                 return ISC_FALSE;
00317         }
00318         if (bits > (addr->len * 8)) {
00319                 return ISC_FALSE;
00320         }
00321 
00322         /*
00323          * Figure out how many low-order bits need to be zero.
00324          */
00325         zero_bits = (addr->len * 8) - bits;
00326         zero_bytes = zero_bits / 8;
00327 
00328         /* 
00329          * Check to make sure the low-order bytes are zero.
00330          */
00331         for (i=1; i<=zero_bytes; i++) {
00332                 if (addr->iabuf[addr->len-i] != 0) {
00333                         return ISC_FALSE;
00334                 }
00335         }
00336 
00337         /* 
00338          * Look to see if any bits not in right-hand bytes are 
00339          * non-zero, by making a byte that has these bits set to zero 
00340          * comparing to the original byte. If these two values are 
00341          * equal, then the right-hand bits are zero, and we are 
00342          * happy.
00343          */
00344         shift_bits = zero_bits % 8;
00345         if (shift_bits == 0) return ISC_TRUE;
00346         byte = addr->iabuf[addr->len-zero_bytes-1];
00347         return (((byte >> shift_bits) << shift_bits) == byte);
00348 }
00349 
00350 /*
00351  * range2cidr
00352  *
00353  * Converts a range of IP addresses to a set of CIDR networks.
00354  *
00355  * Examples: 
00356  *  192.168.0.0 - 192.168.0.255 = 192.168.0.0/24
00357  *  10.0.0.0 - 10.0.1.127 = 10.0.0.0/24, 10.0.1.0/25
00358  *  255.255.255.32 - 255.255.255.255 = 255.255.255.32/27, 255.255.255.64/26,
00359  *                                     255.255.255.128/25
00360  */
00361 isc_result_t 
00362 range2cidr(struct iaddrcidrnetlist **result, 
00363            const struct iaddr *lo, const struct iaddr *hi) {
00364         struct iaddr addr;
00365         struct iaddr mask;
00366         int bit;
00367         struct iaddr end_addr;
00368         struct iaddr dummy;
00369         int ofs, val;
00370         struct iaddrcidrnetlist *net;
00371         int tmp;
00372 
00373         if (result == NULL) {
00374                 return DHCP_R_INVALIDARG;
00375         }
00376         if (*result != NULL) {
00377                 return DHCP_R_INVALIDARG;
00378         }
00379         if ((lo == NULL) || (hi == NULL) || (lo->len != hi->len)) {
00380                 return DHCP_R_INVALIDARG;
00381         }
00382 
00383         /*
00384          * Put our start and end in the right order, if reversed.
00385          */
00386         if (addr_cmp(lo, hi) > 0) {
00387                 const struct iaddr *tmp;
00388                 tmp = lo;
00389                 lo = hi;
00390                 hi = tmp;
00391         }
00392 
00393         /*
00394          * Theory of operation:
00395          *
00396          * -------------------
00397          * Start at the low end, and keep trying larger networks
00398          * until we get one that is too big (explained below).
00399          *
00400          * We keep a "mask", which is the ones-complement of a 
00401          * normal netmask. So, a /23 has a netmask of 255.255.254.0,
00402          * and a mask of 0.0.1.255.
00403          *
00404          * We know when a network is too big when we bitwise-AND the 
00405          * mask with the starting address and we get a non-zero 
00406          * result, like this:
00407          *
00408          *    addr: 192.168.1.0, mask: 0.0.1.255
00409          *    bitwise-AND: 0.0.1.0
00410          * 
00411          * A network is also too big if the bitwise-OR of the mask
00412          * with the starting address is larger than the end address,
00413          * like this:
00414          *
00415          *    start: 192.168.1.0, mask: 0.0.1.255, end: 192.168.0.255
00416          *    bitwise-OR: 192.168.1.255 
00417          *
00418          * -------------------
00419          * Once we have found a network that is too big, we add the 
00420          * appropriate CIDR network to our list of found networks.
00421          *
00422          * We then use the next IP address as our low address, and
00423          * begin the process of searching for a network that is 
00424          * too big again, starting with an empty mask.
00425          */
00426         addr = *lo;
00427         bit = 0;
00428         memset(&mask, 0, sizeof(mask));
00429         mask.len = addr.len;
00430         while (addr_cmp(&addr, hi) <= 0) {
00431                 /*
00432                  * Bitwise-OR mask with (1 << bit)
00433                  */
00434                 ofs = addr.len - (bit / 8) - 1;
00435                 val = 1 << (bit % 8);
00436                 if (ofs >= 0) {
00437                         mask.iabuf[ofs] |= val;
00438                 }
00439 
00440                 /* 
00441                  * See if we're too big, and save this network if so.
00442                  */
00443                 addr_or(&end_addr, &addr, &mask);
00444                 if ((ofs < 0) ||
00445                     (addr_cmp(&end_addr, hi) > 0) || 
00446                     addr_and(&dummy, &addr, &mask)) {
00447                         /*
00448                          * Add a new prefix to our list.
00449                          */
00450                         net = dmalloc(sizeof(*net), MDL);
00451                         if (net == NULL) {
00452                                 while (*result != NULL) {
00453                                         net = (*result)->next;
00454                                         dfree(*result, MDL);
00455                                         *result = net;
00456                                 }
00457                                 return ISC_R_NOMEMORY;
00458                         }
00459                         net->cidrnet.lo_addr = addr;
00460                         net->cidrnet.bits = (addr.len * 8) - bit;
00461                         net->next = *result;
00462                         *result = net;
00463 
00464                         /* 
00465                          * Figure out our new starting address, 
00466                          * by adding (1 << bit) to our previous
00467                          * starting address.
00468                          */
00469                         tmp = addr.iabuf[ofs] + val;
00470                         while ((ofs >= 0) && (tmp > 255)) {
00471                                 addr.iabuf[ofs] = tmp - 256;
00472                                 ofs--;
00473                                 tmp = addr.iabuf[ofs] + 1;
00474                         }
00475                         if (ofs < 0) {
00476                                 /* Gone past last address, we're done. */
00477                                 break;
00478                         }
00479                         addr.iabuf[ofs] = tmp;
00480 
00481                         /*
00482                          * Reset our bit and mask.
00483                          */
00484                         bit = 0;
00485                         memset(mask.iabuf, 0, sizeof(mask.iabuf));
00486                         memset(end_addr.iabuf, 0, sizeof(end_addr.iabuf));
00487                 } else {
00488                         /*
00489                          * If we're not too big, increase our network size.
00490                          */
00491                         bit++;
00492                 }
00493         }
00494 
00495         /*
00496          * We're done.
00497          */
00498         return ISC_R_SUCCESS;
00499 }
00500 
00501 /*
00502  * Free a list of CIDR networks, such as returned from range2cidr().
00503  */
00504 isc_result_t
00505 free_iaddrcidrnetlist(struct iaddrcidrnetlist **result) {
00506         struct iaddrcidrnetlist *p;
00507 
00508         if (result == NULL) {
00509                 return DHCP_R_INVALIDARG;
00510         }
00511         if (*result == NULL) {
00512                 return DHCP_R_INVALIDARG;
00513         }
00514 
00515         while (*result != NULL) {
00516                 p = *result;
00517                 *result = p->next;
00518                 dfree(p, MDL);
00519         }
00520 
00521         return ISC_R_SUCCESS;
00522 }
00523 
00524 static const char *
00525 inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size)
00526 {
00527         char tmp[sizeof("32.255.255.255.255")];
00528         int len;
00529 
00530         switch (srclen) {
00531                 case 2:
00532                         len = sprintf (tmp, "%u.%u", src[0], src[1]);
00533                         break;
00534                 case 3:
00535                         len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]);
00536                         break;
00537                 case 4:
00538                         len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
00539                         break;
00540                 case 5:
00541                         len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]);
00542                         break;
00543                 default:
00544                         return NULL;
00545         }
00546         if (len < 0)
00547                 return NULL;
00548 
00549         if (len > size) {
00550                 errno = ENOSPC;
00551                 return NULL;
00552         }
00553 
00554         return strcpy (dst, tmp);
00555 }
00556 
00557 /* pdestdesc() turns an iaddr structure into a printable dest. descriptor */
00558 const char *
00559 pdestdesc(const struct iaddr addr) {
00560         static char pbuf[sizeof("255.255.255.255.255")];
00561 
00562         if (addr.len == 0) {
00563                 return "<null destination descriptor>";
00564         }
00565         if (addr.len == 1) {
00566                 return "0";
00567         }
00568         if ((addr.len >= 2) && (addr.len <= 5)) {
00569                 return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf));
00570         }
00571 
00572         log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.",
00573                   MDL, addr.len);
00574         /* quell compiler warnings */
00575         return NULL;
00576 }
00577 
00578 /* piaddr() turns an iaddr structure into a printable address. */
00579 /* XXX: should use a const pointer rather than passing the structure */
00580 const char *
00581 piaddr(const struct iaddr addr) {
00582         static char
00583                 pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
00584                          /* "255.255.255.255" */
00585 
00586         /* INSIST((addr.len == 0) || (addr.len == 4) || (addr.len == 16)); */
00587 
00588         if (addr.len == 0) {
00589                 return "<null address>";
00590         }
00591         if (addr.len == 4) {
00592                 return inet_ntop(AF_INET, addr.iabuf, pbuf, sizeof(pbuf));
00593         } 
00594         if (addr.len == 16) {
00595                 return inet_ntop(AF_INET6, addr.iabuf, pbuf, sizeof(pbuf));
00596         }
00597 
00598         log_fatal("piaddr():%s:%d: Invalid address length %d.", MDL,
00599                   addr.len);
00600         /* quell compiler warnings */
00601         return NULL;
00602 }
00603 
00604 /* piaddrmask takes an iaddr structure mask, determines the bitlength of
00605  * the mask, and then returns the printable CIDR notation of the two.
00606  */
00607 char *
00608 piaddrmask(struct iaddr *addr, struct iaddr *mask) {
00609         int mw;
00610         unsigned int oct, bit;
00611 
00612         if ((addr->len != 4) && (addr->len != 16))
00613                 log_fatal("piaddrmask():%s:%d: Address length %d invalid",
00614                           MDL, addr->len);
00615         if (addr->len != mask->len)
00616                 log_fatal("piaddrmask():%s:%d: Address and mask size mismatch",
00617                           MDL);
00618 
00619         /* Determine netmask width in bits. */
00620         for (mw = (mask->len * 8) ; mw > 0 ; ) {
00621                 oct = (mw - 1) / 8;
00622                 bit = 0x80 >> ((mw - 1) % 8);
00623                 if (!mask->iabuf[oct])
00624                         mw -= 8;
00625                 else if (mask->iabuf[oct] & bit)
00626                         break;
00627                 else
00628                         mw--;
00629         }
00630 
00631         if (mw < 0)
00632                 log_fatal("Impossible condition at %s:%d.", MDL);
00633 
00634         return piaddrcidr(addr, mw);
00635 }
00636 
00637 /* Format an address and mask-length into printable CIDR notation. */
00638 char *
00639 piaddrcidr(const struct iaddr *addr, unsigned int bits) {
00640         static char
00641             ret[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128")];
00642                     /* "255.255.255.255/32" */
00643 
00644         /* INSIST(addr != NULL); */
00645         /* INSIST((addr->len == 4) || (addr->len == 16)); */
00646         /* INSIST(bits <= (addr->len * 8)); */
00647 
00648         if (bits > (addr->len * 8))
00649                 return NULL;
00650 
00651         sprintf(ret, "%s/%d", piaddr(*addr), bits);
00652 
00653         return ret;
00654 }
00655 
00656 /* Validate that the string represents a valid port number and
00657  * return it in network byte order
00658  */
00659 
00660 u_int16_t
00661 validate_port(char *port) {
00662         long local_port = 0;
00663         long lower = 1;
00664         long upper = 65535;
00665         char *endptr;
00666 
00667         errno = 0;
00668         local_port = strtol(port, &endptr, 10);
00669         
00670         if ((*endptr != '\0') || (errno == ERANGE) || (errno == EINVAL))
00671                 log_fatal ("Invalid port number specification: %s", port);
00672 
00673         if (local_port < lower || local_port > upper)
00674                 log_fatal("Port number specified is out of range (%ld-%ld).",
00675                           lower, upper);
00676 
00677         return htons((u_int16_t)local_port);
00678 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1