File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / inet.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    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>