File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc / sockaddr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
    3:  * Copyright (C) 1999-2003  Internet Software Consortium.
    4:  *
    5:  * Permission to use, copy, modify, and/or distribute this software for any
    6:  * purpose with or without fee is hereby granted, provided that the above
    7:  * copyright notice and this permission notice appear in all copies.
    8:  *
    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
   10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
   11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
   12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
   14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   15:  * PERFORMANCE OF THIS SOFTWARE.
   16:  */
   17: 
   18: /* $Id: sockaddr.c,v 1.1.1.1 2012/05/29 12:08:38 misho Exp $ */
   19: 
   20: /*! \file */
   21: 
   22: #include <config.h>
   23: 
   24: #include <stdio.h>
   25: 
   26: #include <isc/buffer.h>
   27: #include <isc/hash.h>
   28: #include <isc/msgs.h>
   29: #include <isc/netaddr.h>
   30: #include <isc/print.h>
   31: #include <isc/region.h>
   32: #include <isc/sockaddr.h>
   33: #include <isc/string.h>
   34: #include <isc/util.h>
   35: 
   36: isc_boolean_t
   37: isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
   38: 	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
   39: 					   ISC_SOCKADDR_CMPPORT|
   40: 					   ISC_SOCKADDR_CMPSCOPE));
   41: }
   42: 
   43: isc_boolean_t
   44: isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
   45: 	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
   46: 					   ISC_SOCKADDR_CMPSCOPE));
   47: }
   48: 
   49: isc_boolean_t
   50: isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
   51: 		     unsigned int flags)
   52: {
   53: 	REQUIRE(a != NULL && b != NULL);
   54: 
   55: 	if (a->length != b->length)
   56: 		return (ISC_FALSE);
   57: 
   58: 	/*
   59: 	 * We don't just memcmp because the sin_zero field isn't always
   60: 	 * zero.
   61: 	 */
   62: 
   63: 	if (a->type.sa.sa_family != b->type.sa.sa_family)
   64: 		return (ISC_FALSE);
   65: 	switch (a->type.sa.sa_family) {
   66: 	case AF_INET:
   67: 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
   68: 		    memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
   69: 			   sizeof(a->type.sin.sin_addr)) != 0)
   70: 			return (ISC_FALSE);
   71: 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
   72: 		    a->type.sin.sin_port != b->type.sin.sin_port)
   73: 			return (ISC_FALSE);
   74: 		break;
   75: 	case AF_INET6:
   76: 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
   77: 		    memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
   78: 			   sizeof(a->type.sin6.sin6_addr)) != 0)
   79: 			return (ISC_FALSE);
   80: #ifdef ISC_PLATFORM_HAVESCOPEID
   81: 		/*
   82: 		 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
   83: 		 * ISC_FALSE if one of the scopes in zero.
   84: 		 */
   85: 		if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
   86: 		    a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
   87: 		    ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
   88: 		      (a->type.sin6.sin6_scope_id != 0 &&
   89: 		       b->type.sin6.sin6_scope_id != 0)))
   90: 			return (ISC_FALSE);
   91: #endif
   92: 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
   93: 		    a->type.sin6.sin6_port != b->type.sin6.sin6_port)
   94: 			return (ISC_FALSE);
   95: 		break;
   96: 	default:
   97: 		if (memcmp(&a->type, &b->type, a->length) != 0)
   98: 			return (ISC_FALSE);
   99: 	}
  100: 	return (ISC_TRUE);
  101: }
  102: 
  103: isc_boolean_t
  104: isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
  105: 			  unsigned int prefixlen)
  106: {
  107: 	isc_netaddr_t na, nb;
  108: 	isc_netaddr_fromsockaddr(&na, a);
  109: 	isc_netaddr_fromsockaddr(&nb, b);
  110: 	return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
  111: }
  112: 
  113: isc_result_t
  114: isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
  115: 	isc_result_t result;
  116: 	isc_netaddr_t netaddr;
  117: 	char pbuf[sizeof("65000")];
  118: 	unsigned int plen;
  119: 	isc_region_t avail;
  120: 
  121: 	REQUIRE(sockaddr != NULL);
  122: 
  123: 	/*
  124: 	 * Do the port first, giving us the opportunity to check for
  125: 	 * unsupported address families before calling
  126: 	 * isc_netaddr_fromsockaddr().
  127: 	 */
  128: 	switch (sockaddr->type.sa.sa_family) {
  129: 	case AF_INET:
  130: 		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
  131: 		break;
  132: 	case AF_INET6:
  133: 		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
  134: 		break;
  135: #ifdef ISC_PLAFORM_HAVESYSUNH
  136: 	case AF_UNIX:
  137: 		plen = strlen(sockaddr->type.sunix.sun_path);
  138: 		if (plen >= isc_buffer_availablelength(target))
  139: 			return (ISC_R_NOSPACE);
  140: 
  141: 		isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
  142: 
  143: 		/*
  144: 		 * Null terminate after used region.
  145: 		 */
  146: 		isc_buffer_availableregion(target, &avail);
  147: 		INSIST(avail.length >= 1);
  148: 		avail.base[0] = '\0';
  149: 
  150: 		return (ISC_R_SUCCESS);
  151: #endif
  152: 	default:
  153: 		return (ISC_R_FAILURE);
  154: 	}
  155: 
  156: 	plen = strlen(pbuf);
  157: 	INSIST(plen < sizeof(pbuf));
  158: 
  159: 	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
  160: 	result = isc_netaddr_totext(&netaddr, target);
  161: 	if (result != ISC_R_SUCCESS)
  162: 		return (result);
  163: 
  164: 	if (1 + plen + 1 > isc_buffer_availablelength(target))
  165: 		return (ISC_R_NOSPACE);
  166: 
  167: 	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
  168: 	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
  169: 
  170: 	/*
  171: 	 * Null terminate after used region.
  172: 	 */
  173: 	isc_buffer_availableregion(target, &avail);
  174: 	INSIST(avail.length >= 1);
  175: 	avail.base[0] = '\0';
  176: 
  177: 	return (ISC_R_SUCCESS);
  178: }
  179: 
  180: void
  181: isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
  182: 	isc_result_t result;
  183: 	isc_buffer_t buf;
  184: 
  185: 	isc_buffer_init(&buf, array, size);
  186: 	result = isc_sockaddr_totext(sa, &buf);
  187: 	if (result != ISC_R_SUCCESS) {
  188: 		/*
  189: 		 * The message is the same as in netaddr.c.
  190: 		 */
  191: 		snprintf(array, size,
  192: 			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
  193: 					ISC_MSG_UNKNOWNADDR,
  194: 					"<unknown address, family %u>"),
  195: 			 sa->type.sa.sa_family);
  196: 		array[size - 1] = '\0';
  197: 	}
  198: }
  199: 
  200: unsigned int
  201: isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
  202: 	unsigned int length = 0;
  203: 	const unsigned char *s = NULL;
  204: 	unsigned int h = 0;
  205: 	unsigned int g;
  206: 	unsigned int p = 0;
  207: 	const struct in6_addr *in6;
  208: 
  209: 	REQUIRE(sockaddr != NULL);
  210: 
  211: 	switch (sockaddr->type.sa.sa_family) {
  212: 	case AF_INET:
  213: 		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
  214: 		p = ntohs(sockaddr->type.sin.sin_port);
  215: 		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
  216: 		break;
  217: 	case AF_INET6:
  218: 		in6 = &sockaddr->type.sin6.sin6_addr;
  219: 		if (IN6_IS_ADDR_V4MAPPED(in6)) {
  220: 			s = (const unsigned char *)&in6[12];
  221: 			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
  222: 		} else {
  223: 			s = (const unsigned char *)in6;
  224: 			length = sizeof(sockaddr->type.sin6.sin6_addr);
  225: 		}
  226: 		p = ntohs(sockaddr->type.sin6.sin6_port);
  227: 		break;
  228: 	default:
  229: 		UNEXPECTED_ERROR(__FILE__, __LINE__,
  230: 				 isc_msgcat_get(isc_msgcat,
  231: 						ISC_MSGSET_SOCKADDR,
  232: 						ISC_MSG_UNKNOWNFAMILY,
  233: 						"unknown address family: %d"),
  234: 					     (int)sockaddr->type.sa.sa_family);
  235: 		s = (const unsigned char *)&sockaddr->type;
  236: 		length = sockaddr->length;
  237: 		p = 0;
  238: 	}
  239: 
  240: 	h = isc_hash_calc(s, length, ISC_TRUE);
  241: 	if (!address_only) {
  242: 		g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
  243: 				  ISC_TRUE);
  244: 		h = h ^ g; /* XXX: we should concatenate h and p first */
  245: 	}
  246: 
  247: 	return (h);
  248: }
  249: 
  250: void
  251: isc_sockaddr_any(isc_sockaddr_t *sockaddr)
  252: {
  253: 	memset(sockaddr, 0, sizeof(*sockaddr));
  254: 	sockaddr->type.sin.sin_family = AF_INET;
  255: #ifdef ISC_PLATFORM_HAVESALEN
  256: 	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
  257: #endif
  258: 	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
  259: 	sockaddr->type.sin.sin_port = 0;
  260: 	sockaddr->length = sizeof(sockaddr->type.sin);
  261: 	ISC_LINK_INIT(sockaddr, link);
  262: }
  263: 
  264: void
  265: isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
  266: {
  267: 	memset(sockaddr, 0, sizeof(*sockaddr));
  268: 	sockaddr->type.sin6.sin6_family = AF_INET6;
  269: #ifdef ISC_PLATFORM_HAVESALEN
  270: 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
  271: #endif
  272: 	sockaddr->type.sin6.sin6_addr = in6addr_any;
  273: 	sockaddr->type.sin6.sin6_port = 0;
  274: 	sockaddr->length = sizeof(sockaddr->type.sin6);
  275: 	ISC_LINK_INIT(sockaddr, link);
  276: }
  277: 
  278: void
  279: isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
  280: 		    in_port_t port)
  281: {
  282: 	memset(sockaddr, 0, sizeof(*sockaddr));
  283: 	sockaddr->type.sin.sin_family = AF_INET;
  284: #ifdef ISC_PLATFORM_HAVESALEN
  285: 	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
  286: #endif
  287: 	sockaddr->type.sin.sin_addr = *ina;
  288: 	sockaddr->type.sin.sin_port = htons(port);
  289: 	sockaddr->length = sizeof(sockaddr->type.sin);
  290: 	ISC_LINK_INIT(sockaddr, link);
  291: }
  292: 
  293: void
  294: isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
  295:      switch (pf) {
  296:      case AF_INET:
  297: 	     isc_sockaddr_any(sockaddr);
  298: 	     break;
  299:      case AF_INET6:
  300: 	     isc_sockaddr_any6(sockaddr);
  301: 	     break;
  302:      default:
  303: 	     INSIST(0);
  304:      }
  305: }
  306: 
  307: void
  308: isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
  309: 		     in_port_t port)
  310: {
  311: 	memset(sockaddr, 0, sizeof(*sockaddr));
  312: 	sockaddr->type.sin6.sin6_family = AF_INET6;
  313: #ifdef ISC_PLATFORM_HAVESALEN
  314: 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
  315: #endif
  316: 	sockaddr->type.sin6.sin6_addr = *ina6;
  317: 	sockaddr->type.sin6.sin6_port = htons(port);
  318: 	sockaddr->length = sizeof(sockaddr->type.sin6);
  319: 	ISC_LINK_INIT(sockaddr, link);
  320: }
  321: 
  322: void
  323: isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
  324: 		      in_port_t port)
  325: {
  326: 	memset(sockaddr, 0, sizeof(*sockaddr));
  327: 	sockaddr->type.sin6.sin6_family = AF_INET6;
  328: #ifdef ISC_PLATFORM_HAVESALEN
  329: 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
  330: #endif
  331: 	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
  332: 	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
  333: 	memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
  334: 	sockaddr->type.sin6.sin6_port = htons(port);
  335: 	sockaddr->length = sizeof(sockaddr->type.sin6);
  336: 	ISC_LINK_INIT(sockaddr, link);
  337: }
  338: 
  339: int
  340: isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
  341: 
  342: 	/*
  343: 	 * Get the protocol family of 'sockaddr'.
  344: 	 */
  345: 
  346: #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
  347: 	/*
  348: 	 * Assume that PF_xxx == AF_xxx for all AF and PF.
  349: 	 */
  350: 	return (sockaddr->type.sa.sa_family);
  351: #else
  352: 	switch (sockaddr->type.sa.sa_family) {
  353: 	case AF_INET:
  354: 		return (PF_INET);
  355: 	case AF_INET6:
  356: 		return (PF_INET6);
  357: 	default:
  358: 		FATAL_ERROR(__FILE__, __LINE__,
  359: 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
  360: 					   ISC_MSG_UNKNOWNFAMILY,
  361: 					   "unknown address family: %d"),
  362: 			    (int)sockaddr->type.sa.sa_family);
  363: 	}
  364: #endif
  365: }
  366: 
  367: void
  368: isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
  369: 		    in_port_t port)
  370: {
  371: 	memset(sockaddr, 0, sizeof(*sockaddr));
  372: 	sockaddr->type.sin.sin_family = (short)na->family;
  373: 	switch (na->family) {
  374: 	case AF_INET:
  375: 		sockaddr->length = sizeof(sockaddr->type.sin);
  376: #ifdef ISC_PLATFORM_HAVESALEN
  377: 		sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
  378: #endif
  379: 		sockaddr->type.sin.sin_addr = na->type.in;
  380: 		sockaddr->type.sin.sin_port = htons(port);
  381: 		break;
  382: 	case AF_INET6:
  383: 		sockaddr->length = sizeof(sockaddr->type.sin6);
  384: #ifdef ISC_PLATFORM_HAVESALEN
  385: 		sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
  386: #endif
  387: 		memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
  388: #ifdef ISC_PLATFORM_HAVESCOPEID
  389: 		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
  390: #endif
  391: 		sockaddr->type.sin6.sin6_port = htons(port);
  392: 		break;
  393:         default:
  394:                 INSIST(0);
  395: 	}
  396: 	ISC_LINK_INIT(sockaddr, link);
  397: }
  398: 
  399: void
  400: isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
  401: 	switch (sockaddr->type.sa.sa_family) {
  402: 	case AF_INET:
  403: 		sockaddr->type.sin.sin_port = htons(port);
  404: 		break;
  405: 	case AF_INET6:
  406: 		sockaddr->type.sin6.sin6_port = htons(port);
  407: 		break;
  408: 	default:
  409: 		FATAL_ERROR(__FILE__, __LINE__,
  410: 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
  411: 					   ISC_MSG_UNKNOWNFAMILY,
  412: 					   "unknown address family: %d"),
  413: 			    (int)sockaddr->type.sa.sa_family);
  414: 	}
  415: }
  416: 
  417: in_port_t
  418: isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
  419: 	in_port_t port = 0;
  420: 
  421: 	switch (sockaddr->type.sa.sa_family) {
  422: 	case AF_INET:
  423: 		port = ntohs(sockaddr->type.sin.sin_port);
  424: 		break;
  425: 	case AF_INET6:
  426: 		port = ntohs(sockaddr->type.sin6.sin6_port);
  427: 		break;
  428: 	default:
  429: 		FATAL_ERROR(__FILE__, __LINE__,
  430: 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
  431: 					   ISC_MSG_UNKNOWNFAMILY,
  432: 					   "unknown address family: %d"),
  433: 			    (int)sockaddr->type.sa.sa_family);
  434: 	}
  435: 
  436: 	return (port);
  437: }
  438: 
  439: isc_boolean_t
  440: isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
  441: 	isc_netaddr_t netaddr;
  442: 
  443: 	if (sockaddr->type.sa.sa_family == AF_INET ||
  444: 	    sockaddr->type.sa.sa_family == AF_INET6) {
  445: 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
  446: 		return (isc_netaddr_ismulticast(&netaddr));
  447: 	}
  448: 	return (ISC_FALSE);
  449: }
  450: 
  451: isc_boolean_t
  452: isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
  453: 	isc_netaddr_t netaddr;
  454: 
  455: 	if (sockaddr->type.sa.sa_family == AF_INET) {
  456: 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
  457: 		return (isc_netaddr_isexperimental(&netaddr));
  458: 	}
  459: 	return (ISC_FALSE);
  460: }
  461: 
  462: isc_boolean_t
  463: isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
  464: 	isc_netaddr_t netaddr;
  465: 
  466: 	if (sockaddr->type.sa.sa_family == AF_INET6) {
  467: 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
  468: 		return (isc_netaddr_issitelocal(&netaddr));
  469: 	}
  470: 	return (ISC_FALSE);
  471: }
  472: 
  473: isc_boolean_t
  474: isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
  475: 	isc_netaddr_t netaddr;
  476: 
  477: 	if (sockaddr->type.sa.sa_family == AF_INET6) {
  478: 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
  479: 		return (isc_netaddr_islinklocal(&netaddr));
  480: 	}
  481: 	return (ISC_FALSE);
  482: }
  483: 
  484: isc_result_t
  485: isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
  486: #ifdef ISC_PLATFORM_HAVESYSUNH
  487: 	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
  488: 		return (ISC_R_NOSPACE);
  489: 	memset(sockaddr, 0, sizeof(*sockaddr));
  490: 	sockaddr->length = sizeof(sockaddr->type.sunix);
  491: 	sockaddr->type.sunix.sun_family = AF_UNIX;
  492: #ifdef ISC_PLATFORM_HAVESALEN
  493: 	sockaddr->type.sunix.sun_len =
  494: 			(unsigned char)sizeof(sockaddr->type.sunix);
  495: #endif
  496: 	strcpy(sockaddr->type.sunix.sun_path, path);
  497: 	return (ISC_R_SUCCESS);
  498: #else
  499: 	UNUSED(sockaddr);
  500: 	UNUSED(path);
  501: 	return (ISC_R_NOTIMPLEMENTED);
  502: #endif
  503: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>