1258945Sroberto/*
2280849Scy * Copyright (C) 2004-2007, 2010-2012  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 1999-2003  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18280849Scy/* $Id$ */
19258945Sroberto
20258945Sroberto/*! \file */
21258945Sroberto
22258945Sroberto#include <config.h>
23258945Sroberto
24258945Sroberto#include <stdio.h>
25258945Sroberto
26258945Sroberto#include <isc/buffer.h>
27258945Sroberto#include <isc/hash.h>
28258945Sroberto#include <isc/msgs.h>
29258945Sroberto#include <isc/netaddr.h>
30258945Sroberto#include <isc/print.h>
31258945Sroberto#include <isc/region.h>
32258945Sroberto#include <isc/sockaddr.h>
33258945Sroberto#include <isc/string.h>
34258945Sroberto#include <isc/util.h>
35258945Sroberto
36258945Srobertoisc_boolean_t
37258945Srobertoisc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
38258945Sroberto	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
39258945Sroberto					   ISC_SOCKADDR_CMPPORT|
40258945Sroberto					   ISC_SOCKADDR_CMPSCOPE));
41258945Sroberto}
42258945Sroberto
43258945Srobertoisc_boolean_t
44258945Srobertoisc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
45258945Sroberto	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
46258945Sroberto					   ISC_SOCKADDR_CMPSCOPE));
47258945Sroberto}
48258945Sroberto
49258945Srobertoisc_boolean_t
50258945Srobertoisc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
51258945Sroberto		     unsigned int flags)
52258945Sroberto{
53258945Sroberto	REQUIRE(a != NULL && b != NULL);
54258945Sroberto
55258945Sroberto	if (a->length != b->length)
56258945Sroberto		return (ISC_FALSE);
57258945Sroberto
58258945Sroberto	/*
59258945Sroberto	 * We don't just memcmp because the sin_zero field isn't always
60258945Sroberto	 * zero.
61258945Sroberto	 */
62258945Sroberto
63258945Sroberto	if (a->type.sa.sa_family != b->type.sa.sa_family)
64258945Sroberto		return (ISC_FALSE);
65258945Sroberto	switch (a->type.sa.sa_family) {
66258945Sroberto	case AF_INET:
67258945Sroberto		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
68258945Sroberto		    memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
69258945Sroberto			   sizeof(a->type.sin.sin_addr)) != 0)
70258945Sroberto			return (ISC_FALSE);
71258945Sroberto		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
72258945Sroberto		    a->type.sin.sin_port != b->type.sin.sin_port)
73258945Sroberto			return (ISC_FALSE);
74258945Sroberto		break;
75258945Sroberto	case AF_INET6:
76258945Sroberto		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
77258945Sroberto		    memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
78258945Sroberto			   sizeof(a->type.sin6.sin6_addr)) != 0)
79258945Sroberto			return (ISC_FALSE);
80258945Sroberto#ifdef ISC_PLATFORM_HAVESCOPEID
81258945Sroberto		/*
82258945Sroberto		 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
83258945Sroberto		 * ISC_FALSE if one of the scopes in zero.
84258945Sroberto		 */
85258945Sroberto		if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
86258945Sroberto		    a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
87258945Sroberto		    ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
88258945Sroberto		      (a->type.sin6.sin6_scope_id != 0 &&
89258945Sroberto		       b->type.sin6.sin6_scope_id != 0)))
90258945Sroberto			return (ISC_FALSE);
91258945Sroberto#endif
92258945Sroberto		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
93258945Sroberto		    a->type.sin6.sin6_port != b->type.sin6.sin6_port)
94258945Sroberto			return (ISC_FALSE);
95258945Sroberto		break;
96258945Sroberto	default:
97258945Sroberto		if (memcmp(&a->type, &b->type, a->length) != 0)
98258945Sroberto			return (ISC_FALSE);
99258945Sroberto	}
100258945Sroberto	return (ISC_TRUE);
101258945Sroberto}
102258945Sroberto
103258945Srobertoisc_boolean_t
104258945Srobertoisc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
105258945Sroberto			  unsigned int prefixlen)
106258945Sroberto{
107258945Sroberto	isc_netaddr_t na, nb;
108258945Sroberto	isc_netaddr_fromsockaddr(&na, a);
109258945Sroberto	isc_netaddr_fromsockaddr(&nb, b);
110258945Sroberto	return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
111258945Sroberto}
112258945Sroberto
113258945Srobertoisc_result_t
114258945Srobertoisc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
115258945Sroberto	isc_result_t result;
116258945Sroberto	isc_netaddr_t netaddr;
117258945Sroberto	char pbuf[sizeof("65000")];
118258945Sroberto	unsigned int plen;
119258945Sroberto	isc_region_t avail;
120258945Sroberto
121258945Sroberto	REQUIRE(sockaddr != NULL);
122258945Sroberto
123258945Sroberto	/*
124258945Sroberto	 * Do the port first, giving us the opportunity to check for
125258945Sroberto	 * unsupported address families before calling
126258945Sroberto	 * isc_netaddr_fromsockaddr().
127258945Sroberto	 */
128258945Sroberto	switch (sockaddr->type.sa.sa_family) {
129258945Sroberto	case AF_INET:
130258945Sroberto		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
131258945Sroberto		break;
132258945Sroberto	case AF_INET6:
133258945Sroberto		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
134258945Sroberto		break;
135258945Sroberto#ifdef ISC_PLAFORM_HAVESYSUNH
136258945Sroberto	case AF_UNIX:
137293894Sglebius		plen = (unsigned int)strlen(sockaddr->type.sunix.sun_path);
138258945Sroberto		if (plen >= isc_buffer_availablelength(target))
139258945Sroberto			return (ISC_R_NOSPACE);
140258945Sroberto
141258945Sroberto		isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
142258945Sroberto
143258945Sroberto		/*
144258945Sroberto		 * Null terminate after used region.
145258945Sroberto		 */
146258945Sroberto		isc_buffer_availableregion(target, &avail);
147258945Sroberto		INSIST(avail.length >= 1);
148258945Sroberto		avail.base[0] = '\0';
149258945Sroberto
150258945Sroberto		return (ISC_R_SUCCESS);
151258945Sroberto#endif
152258945Sroberto	default:
153258945Sroberto		return (ISC_R_FAILURE);
154258945Sroberto	}
155258945Sroberto
156293894Sglebius	plen = (unsigned int)strlen(pbuf);
157258945Sroberto	INSIST(plen < sizeof(pbuf));
158258945Sroberto
159258945Sroberto	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
160258945Sroberto	result = isc_netaddr_totext(&netaddr, target);
161258945Sroberto	if (result != ISC_R_SUCCESS)
162258945Sroberto		return (result);
163258945Sroberto
164258945Sroberto	if (1 + plen + 1 > isc_buffer_availablelength(target))
165258945Sroberto		return (ISC_R_NOSPACE);
166258945Sroberto
167258945Sroberto	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
168258945Sroberto	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
169258945Sroberto
170258945Sroberto	/*
171258945Sroberto	 * Null terminate after used region.
172258945Sroberto	 */
173258945Sroberto	isc_buffer_availableregion(target, &avail);
174258945Sroberto	INSIST(avail.length >= 1);
175258945Sroberto	avail.base[0] = '\0';
176258945Sroberto
177258945Sroberto	return (ISC_R_SUCCESS);
178258945Sroberto}
179258945Sroberto
180258945Srobertovoid
181258945Srobertoisc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
182258945Sroberto	isc_result_t result;
183258945Sroberto	isc_buffer_t buf;
184258945Sroberto
185280849Scy	if (size == 0U)
186280849Scy		return;
187280849Scy
188258945Sroberto	isc_buffer_init(&buf, array, size);
189258945Sroberto	result = isc_sockaddr_totext(sa, &buf);
190258945Sroberto	if (result != ISC_R_SUCCESS) {
191258945Sroberto		/*
192258945Sroberto		 * The message is the same as in netaddr.c.
193258945Sroberto		 */
194258945Sroberto		snprintf(array, size,
195280849Scy			 "<%s %u>",
196258945Sroberto			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
197258945Sroberto					ISC_MSG_UNKNOWNADDR,
198280849Scy					"unknown address, family"),
199258945Sroberto			 sa->type.sa.sa_family);
200258945Sroberto		array[size - 1] = '\0';
201258945Sroberto	}
202258945Sroberto}
203258945Sroberto
204258945Srobertounsigned int
205258945Srobertoisc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
206258945Sroberto	unsigned int length = 0;
207258945Sroberto	const unsigned char *s = NULL;
208258945Sroberto	unsigned int h = 0;
209258945Sroberto	unsigned int g;
210258945Sroberto	unsigned int p = 0;
211258945Sroberto	const struct in6_addr *in6;
212258945Sroberto
213258945Sroberto	REQUIRE(sockaddr != NULL);
214258945Sroberto
215258945Sroberto	switch (sockaddr->type.sa.sa_family) {
216258945Sroberto	case AF_INET:
217258945Sroberto		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
218258945Sroberto		p = ntohs(sockaddr->type.sin.sin_port);
219258945Sroberto		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
220258945Sroberto		break;
221258945Sroberto	case AF_INET6:
222258945Sroberto		in6 = &sockaddr->type.sin6.sin6_addr;
223258945Sroberto		if (IN6_IS_ADDR_V4MAPPED(in6)) {
224280849Scy			s = (const unsigned char *)&in6 + 12;
225258945Sroberto			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
226258945Sroberto		} else {
227258945Sroberto			s = (const unsigned char *)in6;
228258945Sroberto			length = sizeof(sockaddr->type.sin6.sin6_addr);
229258945Sroberto		}
230258945Sroberto		p = ntohs(sockaddr->type.sin6.sin6_port);
231258945Sroberto		break;
232258945Sroberto	default:
233258945Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
234280849Scy				 "%s: %d",
235258945Sroberto				 isc_msgcat_get(isc_msgcat,
236258945Sroberto						ISC_MSGSET_SOCKADDR,
237258945Sroberto						ISC_MSG_UNKNOWNFAMILY,
238280849Scy						"unknown address family"),
239258945Sroberto					     (int)sockaddr->type.sa.sa_family);
240258945Sroberto		s = (const unsigned char *)&sockaddr->type;
241258945Sroberto		length = sockaddr->length;
242258945Sroberto		p = 0;
243258945Sroberto	}
244258945Sroberto
245258945Sroberto	h = isc_hash_calc(s, length, ISC_TRUE);
246258945Sroberto	if (!address_only) {
247258945Sroberto		g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
248258945Sroberto				  ISC_TRUE);
249258945Sroberto		h = h ^ g; /* XXX: we should concatenate h and p first */
250258945Sroberto	}
251258945Sroberto
252258945Sroberto	return (h);
253258945Sroberto}
254258945Sroberto
255258945Srobertovoid
256258945Srobertoisc_sockaddr_any(isc_sockaddr_t *sockaddr)
257258945Sroberto{
258258945Sroberto	memset(sockaddr, 0, sizeof(*sockaddr));
259258945Sroberto	sockaddr->type.sin.sin_family = AF_INET;
260258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
261258945Sroberto	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
262258945Sroberto#endif
263258945Sroberto	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
264258945Sroberto	sockaddr->type.sin.sin_port = 0;
265258945Sroberto	sockaddr->length = sizeof(sockaddr->type.sin);
266258945Sroberto	ISC_LINK_INIT(sockaddr, link);
267258945Sroberto}
268258945Sroberto
269258945Srobertovoid
270258945Srobertoisc_sockaddr_any6(isc_sockaddr_t *sockaddr)
271258945Sroberto{
272258945Sroberto	memset(sockaddr, 0, sizeof(*sockaddr));
273258945Sroberto	sockaddr->type.sin6.sin6_family = AF_INET6;
274258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
275258945Sroberto	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
276258945Sroberto#endif
277258945Sroberto	sockaddr->type.sin6.sin6_addr = in6addr_any;
278258945Sroberto	sockaddr->type.sin6.sin6_port = 0;
279258945Sroberto	sockaddr->length = sizeof(sockaddr->type.sin6);
280258945Sroberto	ISC_LINK_INIT(sockaddr, link);
281258945Sroberto}
282258945Sroberto
283258945Srobertovoid
284258945Srobertoisc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
285258945Sroberto		    in_port_t port)
286258945Sroberto{
287258945Sroberto	memset(sockaddr, 0, sizeof(*sockaddr));
288258945Sroberto	sockaddr->type.sin.sin_family = AF_INET;
289258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
290258945Sroberto	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
291258945Sroberto#endif
292258945Sroberto	sockaddr->type.sin.sin_addr = *ina;
293258945Sroberto	sockaddr->type.sin.sin_port = htons(port);
294258945Sroberto	sockaddr->length = sizeof(sockaddr->type.sin);
295258945Sroberto	ISC_LINK_INIT(sockaddr, link);
296258945Sroberto}
297258945Sroberto
298258945Srobertovoid
299258945Srobertoisc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
300258945Sroberto     switch (pf) {
301258945Sroberto     case AF_INET:
302258945Sroberto	     isc_sockaddr_any(sockaddr);
303258945Sroberto	     break;
304258945Sroberto     case AF_INET6:
305258945Sroberto	     isc_sockaddr_any6(sockaddr);
306258945Sroberto	     break;
307258945Sroberto     default:
308258945Sroberto	     INSIST(0);
309258945Sroberto     }
310258945Sroberto}
311258945Sroberto
312258945Srobertovoid
313258945Srobertoisc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
314258945Sroberto		     in_port_t port)
315258945Sroberto{
316258945Sroberto	memset(sockaddr, 0, sizeof(*sockaddr));
317258945Sroberto	sockaddr->type.sin6.sin6_family = AF_INET6;
318258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
319258945Sroberto	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
320258945Sroberto#endif
321258945Sroberto	sockaddr->type.sin6.sin6_addr = *ina6;
322258945Sroberto	sockaddr->type.sin6.sin6_port = htons(port);
323258945Sroberto	sockaddr->length = sizeof(sockaddr->type.sin6);
324258945Sroberto	ISC_LINK_INIT(sockaddr, link);
325258945Sroberto}
326258945Sroberto
327258945Srobertovoid
328258945Srobertoisc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
329258945Sroberto		      in_port_t port)
330258945Sroberto{
331258945Sroberto	memset(sockaddr, 0, sizeof(*sockaddr));
332258945Sroberto	sockaddr->type.sin6.sin6_family = AF_INET6;
333258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
334258945Sroberto	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
335258945Sroberto#endif
336258945Sroberto	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
337258945Sroberto	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
338258945Sroberto	memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
339258945Sroberto	sockaddr->type.sin6.sin6_port = htons(port);
340258945Sroberto	sockaddr->length = sizeof(sockaddr->type.sin6);
341258945Sroberto	ISC_LINK_INIT(sockaddr, link);
342258945Sroberto}
343258945Sroberto
344258945Srobertoint
345258945Srobertoisc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
346258945Sroberto
347258945Sroberto	/*
348258945Sroberto	 * Get the protocol family of 'sockaddr'.
349258945Sroberto	 */
350258945Sroberto
351258945Sroberto#if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
352258945Sroberto	/*
353258945Sroberto	 * Assume that PF_xxx == AF_xxx for all AF and PF.
354258945Sroberto	 */
355258945Sroberto	return (sockaddr->type.sa.sa_family);
356258945Sroberto#else
357258945Sroberto	switch (sockaddr->type.sa.sa_family) {
358258945Sroberto	case AF_INET:
359258945Sroberto		return (PF_INET);
360258945Sroberto	case AF_INET6:
361258945Sroberto		return (PF_INET6);
362258945Sroberto	default:
363258945Sroberto		FATAL_ERROR(__FILE__, __LINE__,
364258945Sroberto			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
365258945Sroberto					   ISC_MSG_UNKNOWNFAMILY,
366258945Sroberto					   "unknown address family: %d"),
367258945Sroberto			    (int)sockaddr->type.sa.sa_family);
368258945Sroberto	}
369258945Sroberto#endif
370258945Sroberto}
371258945Sroberto
372258945Srobertovoid
373258945Srobertoisc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
374258945Sroberto		    in_port_t port)
375258945Sroberto{
376258945Sroberto	memset(sockaddr, 0, sizeof(*sockaddr));
377258945Sroberto	sockaddr->type.sin.sin_family = (short)na->family;
378258945Sroberto	switch (na->family) {
379258945Sroberto	case AF_INET:
380258945Sroberto		sockaddr->length = sizeof(sockaddr->type.sin);
381258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
382258945Sroberto		sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
383258945Sroberto#endif
384258945Sroberto		sockaddr->type.sin.sin_addr = na->type.in;
385258945Sroberto		sockaddr->type.sin.sin_port = htons(port);
386258945Sroberto		break;
387258945Sroberto	case AF_INET6:
388258945Sroberto		sockaddr->length = sizeof(sockaddr->type.sin6);
389258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
390258945Sroberto		sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
391258945Sroberto#endif
392258945Sroberto		memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
393258945Sroberto#ifdef ISC_PLATFORM_HAVESCOPEID
394258945Sroberto		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
395258945Sroberto#endif
396258945Sroberto		sockaddr->type.sin6.sin6_port = htons(port);
397258945Sroberto		break;
398280849Scy	default:
399280849Scy		INSIST(0);
400258945Sroberto	}
401258945Sroberto	ISC_LINK_INIT(sockaddr, link);
402258945Sroberto}
403258945Sroberto
404258945Srobertovoid
405258945Srobertoisc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
406258945Sroberto	switch (sockaddr->type.sa.sa_family) {
407258945Sroberto	case AF_INET:
408258945Sroberto		sockaddr->type.sin.sin_port = htons(port);
409258945Sroberto		break;
410258945Sroberto	case AF_INET6:
411258945Sroberto		sockaddr->type.sin6.sin6_port = htons(port);
412258945Sroberto		break;
413258945Sroberto	default:
414258945Sroberto		FATAL_ERROR(__FILE__, __LINE__,
415280849Scy			    "%s: %d",
416258945Sroberto			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
417258945Sroberto					   ISC_MSG_UNKNOWNFAMILY,
418280849Scy					   "unknown address family"),
419258945Sroberto			    (int)sockaddr->type.sa.sa_family);
420258945Sroberto	}
421258945Sroberto}
422258945Sroberto
423258945Srobertoin_port_t
424258945Srobertoisc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
425258945Sroberto	in_port_t port = 0;
426258945Sroberto
427258945Sroberto	switch (sockaddr->type.sa.sa_family) {
428258945Sroberto	case AF_INET:
429258945Sroberto		port = ntohs(sockaddr->type.sin.sin_port);
430258945Sroberto		break;
431258945Sroberto	case AF_INET6:
432258945Sroberto		port = ntohs(sockaddr->type.sin6.sin6_port);
433258945Sroberto		break;
434258945Sroberto	default:
435258945Sroberto		FATAL_ERROR(__FILE__, __LINE__,
436280849Scy			    "%s: %d",
437258945Sroberto			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
438258945Sroberto					   ISC_MSG_UNKNOWNFAMILY,
439280849Scy					   "unknown address family"),
440258945Sroberto			    (int)sockaddr->type.sa.sa_family);
441258945Sroberto	}
442258945Sroberto
443258945Sroberto	return (port);
444258945Sroberto}
445258945Sroberto
446258945Srobertoisc_boolean_t
447258945Srobertoisc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
448258945Sroberto	isc_netaddr_t netaddr;
449258945Sroberto
450258945Sroberto	if (sockaddr->type.sa.sa_family == AF_INET ||
451258945Sroberto	    sockaddr->type.sa.sa_family == AF_INET6) {
452258945Sroberto		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
453258945Sroberto		return (isc_netaddr_ismulticast(&netaddr));
454258945Sroberto	}
455258945Sroberto	return (ISC_FALSE);
456258945Sroberto}
457258945Sroberto
458258945Srobertoisc_boolean_t
459258945Srobertoisc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
460258945Sroberto	isc_netaddr_t netaddr;
461258945Sroberto
462258945Sroberto	if (sockaddr->type.sa.sa_family == AF_INET) {
463258945Sroberto		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
464258945Sroberto		return (isc_netaddr_isexperimental(&netaddr));
465258945Sroberto	}
466258945Sroberto	return (ISC_FALSE);
467258945Sroberto}
468258945Sroberto
469258945Srobertoisc_boolean_t
470258945Srobertoisc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
471258945Sroberto	isc_netaddr_t netaddr;
472258945Sroberto
473258945Sroberto	if (sockaddr->type.sa.sa_family == AF_INET6) {
474258945Sroberto		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
475258945Sroberto		return (isc_netaddr_issitelocal(&netaddr));
476258945Sroberto	}
477258945Sroberto	return (ISC_FALSE);
478258945Sroberto}
479258945Sroberto
480258945Srobertoisc_boolean_t
481258945Srobertoisc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
482258945Sroberto	isc_netaddr_t netaddr;
483258945Sroberto
484258945Sroberto	if (sockaddr->type.sa.sa_family == AF_INET6) {
485258945Sroberto		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
486258945Sroberto		return (isc_netaddr_islinklocal(&netaddr));
487258945Sroberto	}
488258945Sroberto	return (ISC_FALSE);
489258945Sroberto}
490258945Sroberto
491258945Srobertoisc_result_t
492258945Srobertoisc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
493258945Sroberto#ifdef ISC_PLATFORM_HAVESYSUNH
494258945Sroberto	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
495258945Sroberto		return (ISC_R_NOSPACE);
496258945Sroberto	memset(sockaddr, 0, sizeof(*sockaddr));
497258945Sroberto	sockaddr->length = sizeof(sockaddr->type.sunix);
498258945Sroberto	sockaddr->type.sunix.sun_family = AF_UNIX;
499258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
500258945Sroberto	sockaddr->type.sunix.sun_len =
501258945Sroberto			(unsigned char)sizeof(sockaddr->type.sunix);
502258945Sroberto#endif
503258945Sroberto	strcpy(sockaddr->type.sunix.sun_path, path);
504258945Sroberto	return (ISC_R_SUCCESS);
505258945Sroberto#else
506258945Sroberto	UNUSED(sockaddr);
507258945Sroberto	UNUSED(path);
508258945Sroberto	return (ISC_R_NOTIMPLEMENTED);
509258945Sroberto#endif
510258945Sroberto}
511