17a6072eroberto/*
2047f369cy * Copyright (C) 2004-2007, 2010-2012  Internet Systems Consortium, Inc. ("ISC")
37a6072eroberto * Copyright (C) 1999-2003  Internet Software Consortium.
47a6072eroberto *
5d54cfbdroberto * Permission to use, copy, modify, and/or distribute this software for any
67a6072eroberto * purpose with or without fee is hereby granted, provided that the above
77a6072eroberto * copyright notice and this permission notice appear in all copies.
87a6072eroberto *
97a6072eroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
107a6072eroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
117a6072eroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
127a6072eroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
137a6072eroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
147a6072eroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
157a6072eroberto * PERFORMANCE OF THIS SOFTWARE.
167a6072eroberto */
177a6072eroberto
18047f369cy/* $Id$ */
197a6072eroberto
20d54cfbdroberto/*! \file */
217a6072eroberto
22d54cfbdroberto#include <config.h>
237a6072eroberto
247a6072eroberto#include <stdio.h>
257a6072eroberto
267a6072eroberto#include <isc/buffer.h>
277a6072eroberto#include <isc/hash.h>
287a6072eroberto#include <isc/msgs.h>
297a6072eroberto#include <isc/netaddr.h>
307a6072eroberto#include <isc/print.h>
317a6072eroberto#include <isc/region.h>
327a6072eroberto#include <isc/sockaddr.h>
337a6072eroberto#include <isc/string.h>
347a6072eroberto#include <isc/util.h>
357a6072eroberto
367a6072erobertoisc_boolean_t
377a6072erobertoisc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
38d54cfbdroberto	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
39d54cfbdroberto					   ISC_SOCKADDR_CMPPORT|
40d54cfbdroberto					   ISC_SOCKADDR_CMPSCOPE));
41d54cfbdroberto}
42d54cfbdroberto
43d54cfbdrobertoisc_boolean_t
44d54cfbdrobertoisc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
45d54cfbdroberto	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
46d54cfbdroberto					   ISC_SOCKADDR_CMPSCOPE));
47d54cfbdroberto}
48d54cfbdroberto
49d54cfbdrobertoisc_boolean_t
50d54cfbdrobertoisc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
51d54cfbdroberto		     unsigned int flags)
52d54cfbdroberto{
537a6072eroberto	REQUIRE(a != NULL && b != NULL);
547a6072eroberto
557a6072eroberto	if (a->length != b->length)
567a6072eroberto		return (ISC_FALSE);
577a6072eroberto
587a6072eroberto	/*
597a6072eroberto	 * We don't just memcmp because the sin_zero field isn't always
607a6072eroberto	 * zero.
617a6072eroberto	 */
627a6072eroberto
637a6072eroberto	if (a->type.sa.sa_family != b->type.sa.sa_family)
647a6072eroberto		return (ISC_FALSE);
657a6072eroberto	switch (a->type.sa.sa_family) {
667a6072eroberto	case AF_INET:
67d54cfbdroberto		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
68d54cfbdroberto		    memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
697a6072eroberto			   sizeof(a->type.sin.sin_addr)) != 0)
707a6072eroberto			return (ISC_FALSE);
71d54cfbdroberto		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
72d54cfbdroberto		    a->type.sin.sin_port != b->type.sin.sin_port)
737a6072eroberto			return (ISC_FALSE);
747a6072eroberto		break;
757a6072eroberto	case AF_INET6:
76d54cfbdroberto		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
77d54cfbdroberto		    memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
787a6072eroberto			   sizeof(a->type.sin6.sin6_addr)) != 0)
797a6072eroberto			return (ISC_FALSE);
807a6072eroberto#ifdef ISC_PLATFORM_HAVESCOPEID
81d54cfbdroberto		/*
82d54cfbdroberto		 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
83d54cfbdroberto		 * ISC_FALSE if one of the scopes in zero.
84d54cfbdroberto		 */
85d54cfbdroberto		if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
86d54cfbdroberto		    a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
87d54cfbdroberto		    ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
88d54cfbdroberto		      (a->type.sin6.sin6_scope_id != 0 &&
89d54cfbdroberto		       b->type.sin6.sin6_scope_id != 0)))
907a6072eroberto			return (ISC_FALSE);
917a6072eroberto#endif
92d54cfbdroberto		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
93d54cfbdroberto		    a->type.sin6.sin6_port != b->type.sin6.sin6_port)
947a6072eroberto			return (ISC_FALSE);
957a6072eroberto		break;
967a6072eroberto	default:
977a6072eroberto		if (memcmp(&a->type, &b->type, a->length) != 0)
987a6072eroberto			return (ISC_FALSE);
997a6072eroberto	}
1007a6072eroberto	return (ISC_TRUE);
1017a6072eroberto}
1027a6072eroberto
1037a6072erobertoisc_boolean_t
1047a6072erobertoisc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
1057a6072eroberto			  unsigned int prefixlen)
1067a6072eroberto{
1077a6072eroberto	isc_netaddr_t na, nb;
1087a6072eroberto	isc_netaddr_fromsockaddr(&na, a);
1097a6072eroberto	isc_netaddr_fromsockaddr(&nb, b);
1107a6072eroberto	return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
1117a6072eroberto}
1127a6072eroberto
1137a6072erobertoisc_result_t
1147a6072erobertoisc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
1157a6072eroberto	isc_result_t result;
1167a6072eroberto	isc_netaddr_t netaddr;
1177a6072eroberto	char pbuf[sizeof("65000")];
1187a6072eroberto	unsigned int plen;
1197a6072eroberto	isc_region_t avail;
1207a6072eroberto
1217a6072eroberto	REQUIRE(sockaddr != NULL);
1227a6072eroberto
1237a6072eroberto	/*
1247a6072eroberto	 * Do the port first, giving us the opportunity to check for
1257a6072eroberto	 * unsupported address families before calling
1267a6072eroberto	 * isc_netaddr_fromsockaddr().
1277a6072eroberto	 */
1287a6072eroberto	switch (sockaddr->type.sa.sa_family) {
1297a6072eroberto	case AF_INET:
1307a6072eroberto		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
1317a6072eroberto		break;
1327a6072eroberto	case AF_INET6:
1337a6072eroberto		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
1347a6072eroberto		break;
135d54cfbdroberto#ifdef ISC_PLAFORM_HAVESYSUNH
136d54cfbdroberto	case AF_UNIX:
1378518518delphij		plen = (unsigned int)strlen(sockaddr->type.sunix.sun_path);
138d54cfbdroberto		if (plen >= isc_buffer_availablelength(target))
139d54cfbdroberto			return (ISC_R_NOSPACE);
140d54cfbdroberto
141d54cfbdroberto		isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
142d54cfbdroberto
143d54cfbdroberto		/*
144d54cfbdroberto		 * Null terminate after used region.
145d54cfbdroberto		 */
146d54cfbdroberto		isc_buffer_availableregion(target, &avail);
147d54cfbdroberto		INSIST(avail.length >= 1);
148d54cfbdroberto		avail.base[0] = '\0';
149d54cfbdroberto
150d54cfbdroberto		return (ISC_R_SUCCESS);
151d54cfbdroberto#endif
1527a6072eroberto	default:
1537a6072eroberto		return (ISC_R_FAILURE);
1547a6072eroberto	}
1557a6072eroberto
1568518518delphij	plen = (unsigned int)strlen(pbuf);
1577a6072eroberto	INSIST(plen < sizeof(pbuf));
1587a6072eroberto
1597a6072eroberto	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
1607a6072eroberto	result = isc_netaddr_totext(&netaddr, target);
1617a6072eroberto	if (result != ISC_R_SUCCESS)
1627a6072eroberto		return (result);
1637a6072eroberto
1647a6072eroberto	if (1 + plen + 1 > isc_buffer_availablelength(target))
1657a6072eroberto		return (ISC_R_NOSPACE);
1667a6072eroberto
1677a6072eroberto	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
1687a6072eroberto	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
1697a6072eroberto
1707a6072eroberto	/*
1717a6072eroberto	 * Null terminate after used region.
1727a6072eroberto	 */
1737a6072eroberto	isc_buffer_availableregion(target, &avail);
1747a6072eroberto	INSIST(avail.length >= 1);
1757a6072eroberto	avail.base[0] = '\0';
1767a6072eroberto
1777a6072eroberto	return (ISC_R_SUCCESS);
1787a6072eroberto}
1797a6072eroberto
1807a6072erobertovoid
1817a6072erobertoisc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
1827a6072eroberto	isc_result_t result;
1837a6072eroberto	isc_buffer_t buf;
1847a6072eroberto
185047f369cy	if (size == 0U)
186047f369cy		return;
187047f369cy
1887a6072eroberto	isc_buffer_init(&buf, array, size);
1897a6072eroberto	result = isc_sockaddr_totext(sa, &buf);
1907a6072eroberto	if (result != ISC_R_SUCCESS) {
1917a6072eroberto		/*
1927a6072eroberto		 * The message is the same as in netaddr.c.
1937a6072eroberto		 */
1947a6072eroberto		snprintf(array, size,
195bdc155dcy			 "<%s %u>",
1967a6072eroberto			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
1977a6072eroberto					ISC_MSG_UNKNOWNADDR,
198bdc155dcy					"unknown address, family"),
1997a6072eroberto			 sa->type.sa.sa_family);
2007a6072eroberto		array[size - 1] = '\0';
2017a6072eroberto	}
2027a6072eroberto}
2037a6072eroberto
2047a6072erobertounsigned int
2057a6072erobertoisc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
2067a6072eroberto	unsigned int length = 0;
2077a6072eroberto	const unsigned char *s = NULL;
2087a6072eroberto	unsigned int h = 0;
2097a6072eroberto	unsigned int g;
2107a6072eroberto	unsigned int p = 0;
2117a6072eroberto	const struct in6_addr *in6;
2127a6072eroberto
2137a6072eroberto	REQUIRE(sockaddr != NULL);
2147a6072eroberto
2157a6072eroberto	switch (sockaddr->type.sa.sa_family) {
2167a6072eroberto	case AF_INET:
2177a6072eroberto		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
2187a6072eroberto		p = ntohs(sockaddr->type.sin.sin_port);
2197a6072eroberto		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
2207a6072eroberto		break;
2217a6072eroberto	case AF_INET6:
2227a6072eroberto		in6 = &sockaddr->type.sin6.sin6_addr;
2237a6072eroberto		if (IN6_IS_ADDR_V4MAPPED(in6)) {
224047f369cy			s = (const unsigned char *)&in6 + 12;
2257a6072eroberto			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
2267a6072eroberto		} else {
2277a6072eroberto			s = (const unsigned char *)in6;
2287a6072eroberto			length = sizeof(sockaddr->type.sin6.sin6_addr);
2297a6072eroberto		}
2307a6072eroberto		p = ntohs(sockaddr->type.sin6.sin6_port);
2317a6072eroberto		break;
2327a6072eroberto	default:
2337a6072eroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
234bdc155dcy				 "%s: %d",
2357a6072eroberto				 isc_msgcat_get(isc_msgcat,
2367a6072eroberto						ISC_MSGSET_SOCKADDR,
2377a6072eroberto						ISC_MSG_UNKNOWNFAMILY,
238bdc155dcy						"unknown address family"),
2397a6072eroberto					     (int)sockaddr->type.sa.sa_family);
2407a6072eroberto		s = (const unsigned char *)&sockaddr->type;
2417a6072eroberto		length = sockaddr->length;
2427a6072eroberto		p = 0;
2437a6072eroberto	}
2447a6072eroberto
2457a6072eroberto	h = isc_hash_calc(s, length, ISC_TRUE);
2467a6072eroberto	if (!address_only) {
2477a6072eroberto		g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
2487a6072eroberto				  ISC_TRUE);
2497a6072eroberto		h = h ^ g; /* XXX: we should concatenate h and p first */
2507a6072eroberto	}
2517a6072eroberto
2527a6072eroberto	return (h);
2537a6072eroberto}
2547a6072eroberto
2557a6072erobertovoid
2567a6072erobertoisc_sockaddr_any(isc_sockaddr_t *sockaddr)
2577a6072eroberto{
2587a6072eroberto	memset(sockaddr, 0, sizeof(*sockaddr));
2597a6072eroberto	sockaddr->type.sin.sin_family = AF_INET;
2607a6072eroberto#ifdef ISC_PLATFORM_HAVESALEN
2617a6072eroberto	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
2627a6072eroberto#endif
2637a6072eroberto	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
2647a6072eroberto	sockaddr->type.sin.sin_port = 0;
2657a6072eroberto	sockaddr->length = sizeof(sockaddr->type.sin);
2667a6072eroberto	ISC_LINK_INIT(sockaddr, link);
2677a6072eroberto}
2687a6072eroberto
2697a6072erobertovoid
2707a6072erobertoisc_sockaddr_any6(isc_sockaddr_t *sockaddr)
2717a6072eroberto{
2727a6072eroberto	memset(sockaddr, 0, sizeof(*sockaddr));
2737a6072eroberto	sockaddr->type.sin6.sin6_family = AF_INET6;
2747a6072eroberto#ifdef ISC_PLATFORM_HAVESALEN
2757a6072eroberto	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
2767a6072eroberto#endif
2777a6072eroberto	sockaddr->type.sin6.sin6_addr = in6addr_any;
2787a6072eroberto	sockaddr->type.sin6.sin6_port = 0;
2797a6072eroberto	sockaddr->length = sizeof(sockaddr->type.sin6);
2807a6072eroberto	ISC_LINK_INIT(sockaddr, link);
2817a6072eroberto}
2827a6072eroberto
2837a6072erobertovoid
2847a6072erobertoisc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
2857a6072eroberto		    in_port_t port)
2867a6072eroberto{
2877a6072eroberto	memset(sockaddr, 0, sizeof(*sockaddr));
2887a6072eroberto	sockaddr->type.sin.sin_family = AF_INET;
2897a6072eroberto#ifdef ISC_PLATFORM_HAVESALEN
2907a6072eroberto	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
2917a6072eroberto#endif
2927a6072eroberto	sockaddr->type.sin.sin_addr = *ina;
2937a6072eroberto	sockaddr->type.sin.sin_port = htons(port);
2947a6072eroberto	sockaddr->length = sizeof(sockaddr->type.sin);
2957a6072eroberto	ISC_LINK_INIT(sockaddr, link);
2967a6072eroberto}
2977a6072eroberto
2987a6072erobertovoid
2997a6072erobertoisc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
3007a6072eroberto     switch (pf) {
3017a6072eroberto     case AF_INET:
3027a6072eroberto	     isc_sockaddr_any(sockaddr);
3037a6072eroberto	     break;
3047a6072eroberto     case AF_INET6:
3057a6072eroberto	     isc_sockaddr_any6(sockaddr);
3067a6072eroberto	     break;
3077a6072eroberto     default:
3087a6072eroberto	     INSIST(0);
3097a6072eroberto     }
3107a6072eroberto}
3117a6072eroberto
3127a6072erobertovoid
3137a6072erobertoisc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
3147a6072eroberto		     in_port_t port)
3157a6072eroberto{
3167a6072eroberto	memset(sockaddr, 0, sizeof(*sockaddr));
3177a6072eroberto	sockaddr->type.sin6.sin6_family = AF_INET6;
3187a6072eroberto#ifdef ISC_PLATFORM_HAVESALEN
3197a6072eroberto	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
3207a6072eroberto#endif
3217a6072eroberto	sockaddr->type.sin6.sin6_addr = *ina6;
3227a6072eroberto	sockaddr->type.sin6.sin6_port = htons(port);
3237a6072eroberto	sockaddr->length = sizeof(sockaddr->type.sin6);
3247a6072eroberto	ISC_LINK_INIT(sockaddr, link);
3257a6072eroberto}
3267a6072eroberto
3277a6072erobertovoid
3287a6072erobertoisc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
3297a6072eroberto		      in_port_t port)
3307a6072eroberto{
3317a6072eroberto	memset(sockaddr, 0, sizeof(*sockaddr));
3327a6072eroberto	sockaddr->type.sin6.sin6_family = AF_INET6;
3337a6072eroberto#ifdef ISC_PLATFORM_HAVESALEN
3347a6072eroberto	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
3357a6072eroberto#endif
3367a6072eroberto	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
3377a6072eroberto	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
3387a6072eroberto	memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
3397a6072eroberto	sockaddr->type.sin6.sin6_port = htons(port);
3407a6072eroberto	sockaddr->length = sizeof(sockaddr->type.sin6);
3417a6072eroberto	ISC_LINK_INIT(sockaddr, link);
3427a6072eroberto}
3437a6072eroberto
3447a6072erobertoint
3457a6072erobertoisc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
3467a6072eroberto
3477a6072eroberto	/*
3487a6072eroberto	 * Get the protocol family of 'sockaddr'.
3497a6072eroberto	 */
3507a6072eroberto
3517a6072eroberto#if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
3527a6072eroberto	/*
3537a6072eroberto	 * Assume that PF_xxx == AF_xxx for all AF and PF.
3547a6072eroberto	 */
3557a6072eroberto	return (sockaddr->type.sa.sa_family);
3567a6072eroberto#else
3577a6072eroberto	switch (sockaddr->type.sa.sa_family) {
3587a6072eroberto	case AF_INET:
3597a6072eroberto		return (PF_INET);
3607a6072eroberto	case AF_INET6:
3617a6072eroberto		return (PF_INET6);
3627a6072eroberto	default:
3637a6072eroberto		FATAL_ERROR(__FILE__, __LINE__,
3647a6072eroberto			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
3657a6072eroberto					   ISC_MSG_UNKNOWNFAMILY,
3667a6072eroberto					   "unknown address family: %d"),
3677a6072eroberto			    (int)sockaddr->type.sa.sa_family);
3687a6072eroberto	}
3697a6072eroberto#endif
3707a6072eroberto}
3717a6072eroberto
3727a6072erobertovoid
3737a6072erobertoisc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
3747a6072eroberto		    in_port_t port)
3757a6072eroberto{
3767a6072eroberto	memset(sockaddr, 0, sizeof(*sockaddr));
377d54cfbdroberto	sockaddr->type.sin.sin_family = (short)na->family;
3787a6072eroberto	switch (na->family) {
3797a6072eroberto	case AF_INET:
3807a6072eroberto		sockaddr->length = sizeof(sockaddr->type.sin);
3817a6072eroberto#ifdef ISC_PLATFORM_HAVESALEN
3827a6072eroberto		sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
3837a6072eroberto#endif
3847a6072eroberto		sockaddr->type.sin.sin_addr = na->type.in;
3857a6072eroberto		sockaddr->type.sin.sin_port = htons(port);
3867a6072eroberto		break;
3877a6072eroberto	case AF_INET6:
3887a6072eroberto		sockaddr->length = sizeof(sockaddr->type.sin6);
3897a6072eroberto#ifdef ISC_PLATFORM_HAVESALEN
3907a6072eroberto		sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
3917a6072eroberto#endif
3927a6072eroberto		memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
3937a6072eroberto#ifdef ISC_PLATFORM_HAVESCOPEID
3947a6072eroberto		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
3957a6072eroberto#endif
3967a6072eroberto		sockaddr->type.sin6.sin6_port = htons(port);
3977a6072eroberto		break;
398047f369cy	default:
399047f369cy		INSIST(0);
4007a6072eroberto	}
4017a6072eroberto	ISC_LINK_INIT(sockaddr, link);
4027a6072eroberto}
4037a6072eroberto
4047a6072erobertovoid
4057a6072erobertoisc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
4067a6072eroberto	switch (sockaddr->type.sa.sa_family) {
4077a6072eroberto	case AF_INET:
4087a6072eroberto		sockaddr->type.sin.sin_port = htons(port);
4097a6072eroberto		break;
4107a6072eroberto	case AF_INET6:
4117a6072eroberto		sockaddr->type.sin6.sin6_port = htons(port);
4127a6072eroberto		break;
4137a6072eroberto	default:
4147a6072eroberto		FATAL_ERROR(__FILE__, __LINE__,
415bdc155dcy			    "%s: %d",
4167a6072eroberto			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
4177a6072eroberto					   ISC_MSG_UNKNOWNFAMILY,
418bdc155dcy					   "unknown address family"),
4197a6072eroberto			    (int)sockaddr->type.sa.sa_family);
4207a6072eroberto	}
4217a6072eroberto}
4227a6072eroberto
4237a6072erobertoin_port_t
424d54cfbdrobertoisc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
4257a6072eroberto	in_port_t port = 0;
4267a6072eroberto
4277a6072eroberto	switch (sockaddr->type.sa.sa_family) {
4287a6072eroberto	case AF_INET:
4297a6072eroberto		port = ntohs(sockaddr->type.sin.sin_port);
4307a6072eroberto		break;
4317a6072eroberto	case AF_INET6:
4327a6072eroberto		port = ntohs(sockaddr->type.sin6.sin6_port);
4337a6072eroberto		break;
4347a6072eroberto	default:
4357a6072eroberto		FATAL_ERROR(__FILE__, __LINE__,
436bdc155dcy			    "%s: %d",
4377a6072eroberto			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
4387a6072eroberto					   ISC_MSG_UNKNOWNFAMILY,
439bdc155dcy					   "unknown address family"),
4407a6072eroberto			    (int)sockaddr->type.sa.sa_family);
4417a6072eroberto	}
4427a6072eroberto
4437a6072eroberto	return (port);
4447a6072eroberto}
4457a6072eroberto
4467a6072erobertoisc_boolean_t
447d54cfbdrobertoisc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
4487a6072eroberto	isc_netaddr_t netaddr;
4497a6072eroberto
450d54cfbdroberto	if (sockaddr->type.sa.sa_family == AF_INET ||
451d54cfbdroberto	    sockaddr->type.sa.sa_family == AF_INET6) {
452d54cfbdroberto		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
453d54cfbdroberto		return (isc_netaddr_ismulticast(&netaddr));
454d54cfbdroberto	}
455d54cfbdroberto	return (ISC_FALSE);
4567a6072eroberto}
4577a6072eroberto
4587a6072erobertoisc_boolean_t
459d54cfbdrobertoisc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
4607a6072eroberto	isc_netaddr_t netaddr;
4617a6072eroberto
4627a6072eroberto	if (sockaddr->type.sa.sa_family == AF_INET) {
4637a6072eroberto		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
4647a6072eroberto		return (isc_netaddr_isexperimental(&netaddr));
4657a6072eroberto	}
4667a6072eroberto	return (ISC_FALSE);
4677a6072eroberto}
4687a6072eroberto
4697a6072erobertoisc_boolean_t
470d54cfbdrobertoisc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
4717a6072eroberto	isc_netaddr_t netaddr;
4727a6072eroberto
4737a6072eroberto	if (sockaddr->type.sa.sa_family == AF_INET6) {
4747a6072eroberto		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
4757a6072eroberto		return (isc_netaddr_issitelocal(&netaddr));
4767a6072eroberto	}
4777a6072eroberto	return (ISC_FALSE);
4787a6072eroberto}
4797a6072eroberto
4807a6072erobertoisc_boolean_t
481d54cfbdrobertoisc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
4827a6072eroberto	isc_netaddr_t netaddr;
4837a6072eroberto
4847a6072eroberto	if (sockaddr->type.sa.sa_family == AF_INET6) {
4857a6072eroberto		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
4867a6072eroberto		return (isc_netaddr_islinklocal(&netaddr));
4877a6072eroberto	}
4887a6072eroberto	return (ISC_FALSE);
4897a6072eroberto}
490d54cfbdroberto
491d54cfbdrobertoisc_result_t
492d54cfbdrobertoisc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
493d54cfbdroberto#ifdef ISC_PLATFORM_HAVESYSUNH
494d54cfbdroberto	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
495d54cfbdroberto		return (ISC_R_NOSPACE);
496d54cfbdroberto	memset(sockaddr, 0, sizeof(*sockaddr));
497d54cfbdroberto	sockaddr->length = sizeof(sockaddr->type.sunix);
498d54cfbdroberto	sockaddr->type.sunix.sun_family = AF_UNIX;
499d54cfbdroberto#ifdef ISC_PLATFORM_HAVESALEN
500d54cfbdroberto	sockaddr->type.sunix.sun_len =
501d54cfbdroberto			(unsigned char)sizeof(sockaddr->type.sunix);
502d54cfbdroberto#endif
503d54cfbdroberto	strcpy(sockaddr->type.sunix.sun_path, path);
504d54cfbdroberto	return (ISC_R_SUCCESS);
505d54cfbdroberto#else
506d54cfbdroberto	UNUSED(sockaddr);
507d54cfbdroberto	UNUSED(path);
508d54cfbdroberto	return (ISC_R_NOTIMPLEMENTED);
509d54cfbdroberto#endif
510d54cfbdroberto}
511