1135446Strhodes/*
2262706Serwin * Copyright (C) 2004-2007, 2010-2012, 2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id$ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <stdio.h>
25135446Strhodes
26135446Strhodes#include <isc/buffer.h>
27135446Strhodes#include <isc/hash.h>
28135446Strhodes#include <isc/msgs.h>
29135446Strhodes#include <isc/netaddr.h>
30135446Strhodes#include <isc/print.h>
31135446Strhodes#include <isc/region.h>
32135446Strhodes#include <isc/sockaddr.h>
33135446Strhodes#include <isc/string.h>
34135446Strhodes#include <isc/util.h>
35135446Strhodes
36135446Strhodesisc_boolean_t
37135446Strhodesisc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
38170222Sdougb	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
39170222Sdougb					   ISC_SOCKADDR_CMPPORT|
40170222Sdougb					   ISC_SOCKADDR_CMPSCOPE));
41170222Sdougb}
42170222Sdougb
43170222Sdougbisc_boolean_t
44170222Sdougbisc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
45170222Sdougb	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
46170222Sdougb					   ISC_SOCKADDR_CMPSCOPE));
47170222Sdougb}
48170222Sdougb
49170222Sdougbisc_boolean_t
50170222Sdougbisc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
51170222Sdougb		     unsigned int flags)
52170222Sdougb{
53135446Strhodes	REQUIRE(a != NULL && b != NULL);
54135446Strhodes
55135446Strhodes	if (a->length != b->length)
56135446Strhodes		return (ISC_FALSE);
57135446Strhodes
58135446Strhodes	/*
59135446Strhodes	 * We don't just memcmp because the sin_zero field isn't always
60135446Strhodes	 * zero.
61135446Strhodes	 */
62135446Strhodes
63135446Strhodes	if (a->type.sa.sa_family != b->type.sa.sa_family)
64135446Strhodes		return (ISC_FALSE);
65135446Strhodes	switch (a->type.sa.sa_family) {
66135446Strhodes	case AF_INET:
67170222Sdougb		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
68170222Sdougb		    memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
69135446Strhodes			   sizeof(a->type.sin.sin_addr)) != 0)
70135446Strhodes			return (ISC_FALSE);
71170222Sdougb		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
72170222Sdougb		    a->type.sin.sin_port != b->type.sin.sin_port)
73135446Strhodes			return (ISC_FALSE);
74135446Strhodes		break;
75135446Strhodes	case AF_INET6:
76170222Sdougb		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
77170222Sdougb		    memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
78135446Strhodes			   sizeof(a->type.sin6.sin6_addr)) != 0)
79135446Strhodes			return (ISC_FALSE);
80135446Strhodes#ifdef ISC_PLATFORM_HAVESCOPEID
81170222Sdougb		/*
82170222Sdougb		 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
83170222Sdougb		 * ISC_FALSE if one of the scopes in zero.
84170222Sdougb		 */
85170222Sdougb		if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
86170222Sdougb		    a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
87170222Sdougb		    ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
88170222Sdougb		      (a->type.sin6.sin6_scope_id != 0 &&
89170222Sdougb		       b->type.sin6.sin6_scope_id != 0)))
90135446Strhodes			return (ISC_FALSE);
91135446Strhodes#endif
92170222Sdougb		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
93170222Sdougb		    a->type.sin6.sin6_port != b->type.sin6.sin6_port)
94135446Strhodes			return (ISC_FALSE);
95135446Strhodes		break;
96135446Strhodes	default:
97135446Strhodes		if (memcmp(&a->type, &b->type, a->length) != 0)
98135446Strhodes			return (ISC_FALSE);
99135446Strhodes	}
100135446Strhodes	return (ISC_TRUE);
101135446Strhodes}
102135446Strhodes
103135446Strhodesisc_boolean_t
104135446Strhodesisc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
105135446Strhodes			  unsigned int prefixlen)
106135446Strhodes{
107135446Strhodes	isc_netaddr_t na, nb;
108135446Strhodes	isc_netaddr_fromsockaddr(&na, a);
109135446Strhodes	isc_netaddr_fromsockaddr(&nb, b);
110135446Strhodes	return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
111135446Strhodes}
112135446Strhodes
113135446Strhodesisc_result_t
114135446Strhodesisc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
115135446Strhodes	isc_result_t result;
116135446Strhodes	isc_netaddr_t netaddr;
117135446Strhodes	char pbuf[sizeof("65000")];
118135446Strhodes	unsigned int plen;
119135446Strhodes	isc_region_t avail;
120135446Strhodes
121135446Strhodes	REQUIRE(sockaddr != NULL);
122135446Strhodes
123135446Strhodes	/*
124135446Strhodes	 * Do the port first, giving us the opportunity to check for
125135446Strhodes	 * unsupported address families before calling
126135446Strhodes	 * isc_netaddr_fromsockaddr().
127135446Strhodes	 */
128135446Strhodes	switch (sockaddr->type.sa.sa_family) {
129135446Strhodes	case AF_INET:
130135446Strhodes		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
131135446Strhodes		break;
132135446Strhodes	case AF_INET6:
133135446Strhodes		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
134135446Strhodes		break;
135170222Sdougb#ifdef ISC_PLAFORM_HAVESYSUNH
136170222Sdougb	case AF_UNIX:
137170222Sdougb		plen = strlen(sockaddr->type.sunix.sun_path);
138170222Sdougb		if (plen >= isc_buffer_availablelength(target))
139170222Sdougb			return (ISC_R_NOSPACE);
140170222Sdougb
141170222Sdougb		isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
142170222Sdougb
143170222Sdougb		/*
144170222Sdougb		 * Null terminate after used region.
145170222Sdougb		 */
146170222Sdougb		isc_buffer_availableregion(target, &avail);
147170222Sdougb		INSIST(avail.length >= 1);
148170222Sdougb		avail.base[0] = '\0';
149170222Sdougb
150170222Sdougb		return (ISC_R_SUCCESS);
151170222Sdougb#endif
152135446Strhodes	default:
153135446Strhodes		return (ISC_R_FAILURE);
154135446Strhodes	}
155135446Strhodes
156135446Strhodes	plen = strlen(pbuf);
157135446Strhodes	INSIST(plen < sizeof(pbuf));
158135446Strhodes
159135446Strhodes	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
160135446Strhodes	result = isc_netaddr_totext(&netaddr, target);
161135446Strhodes	if (result != ISC_R_SUCCESS)
162135446Strhodes		return (result);
163135446Strhodes
164135446Strhodes	if (1 + plen + 1 > isc_buffer_availablelength(target))
165135446Strhodes		return (ISC_R_NOSPACE);
166135446Strhodes
167135446Strhodes	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
168135446Strhodes	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
169135446Strhodes
170135446Strhodes	/*
171135446Strhodes	 * Null terminate after used region.
172135446Strhodes	 */
173135446Strhodes	isc_buffer_availableregion(target, &avail);
174135446Strhodes	INSIST(avail.length >= 1);
175135446Strhodes	avail.base[0] = '\0';
176135446Strhodes
177135446Strhodes	return (ISC_R_SUCCESS);
178135446Strhodes}
179135446Strhodes
180135446Strhodesvoid
181135446Strhodesisc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
182135446Strhodes	isc_result_t result;
183135446Strhodes	isc_buffer_t buf;
184135446Strhodes
185225361Sdougb	if (size == 0U)
186225361Sdougb		return;
187225361Sdougb
188135446Strhodes	isc_buffer_init(&buf, array, size);
189135446Strhodes	result = isc_sockaddr_totext(sa, &buf);
190135446Strhodes	if (result != ISC_R_SUCCESS) {
191135446Strhodes		/*
192135446Strhodes		 * The message is the same as in netaddr.c.
193135446Strhodes		 */
194135446Strhodes		snprintf(array, size,
195135446Strhodes			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
196135446Strhodes					ISC_MSG_UNKNOWNADDR,
197135446Strhodes					"<unknown address, family %u>"),
198135446Strhodes			 sa->type.sa.sa_family);
199135446Strhodes		array[size - 1] = '\0';
200135446Strhodes	}
201135446Strhodes}
202135446Strhodes
203135446Strhodesunsigned int
204135446Strhodesisc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
205135446Strhodes	unsigned int length = 0;
206135446Strhodes	const unsigned char *s = NULL;
207135446Strhodes	unsigned int h = 0;
208135446Strhodes	unsigned int g;
209135446Strhodes	unsigned int p = 0;
210135446Strhodes	const struct in6_addr *in6;
211135446Strhodes
212135446Strhodes	REQUIRE(sockaddr != NULL);
213135446Strhodes
214135446Strhodes	switch (sockaddr->type.sa.sa_family) {
215135446Strhodes	case AF_INET:
216135446Strhodes		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
217135446Strhodes		p = ntohs(sockaddr->type.sin.sin_port);
218135446Strhodes		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
219135446Strhodes		break;
220135446Strhodes	case AF_INET6:
221135446Strhodes		in6 = &sockaddr->type.sin6.sin6_addr;
222254402Serwin		s = (const unsigned char *)in6;
223135446Strhodes		if (IN6_IS_ADDR_V4MAPPED(in6)) {
224254402Serwin			s += 12;
225135446Strhodes			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
226254402Serwin		} else
227135446Strhodes			length = sizeof(sockaddr->type.sin6.sin6_addr);
228135446Strhodes		p = ntohs(sockaddr->type.sin6.sin6_port);
229135446Strhodes		break;
230135446Strhodes	default:
231135446Strhodes		UNEXPECTED_ERROR(__FILE__, __LINE__,
232135446Strhodes				 isc_msgcat_get(isc_msgcat,
233135446Strhodes						ISC_MSGSET_SOCKADDR,
234135446Strhodes						ISC_MSG_UNKNOWNFAMILY,
235135446Strhodes						"unknown address family: %d"),
236135446Strhodes					     (int)sockaddr->type.sa.sa_family);
237135446Strhodes		s = (const unsigned char *)&sockaddr->type;
238135446Strhodes		length = sockaddr->length;
239135446Strhodes		p = 0;
240135446Strhodes	}
241135446Strhodes
242135446Strhodes	h = isc_hash_calc(s, length, ISC_TRUE);
243135446Strhodes	if (!address_only) {
244135446Strhodes		g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
245135446Strhodes				  ISC_TRUE);
246135446Strhodes		h = h ^ g; /* XXX: we should concatenate h and p first */
247135446Strhodes	}
248135446Strhodes
249135446Strhodes	return (h);
250135446Strhodes}
251135446Strhodes
252135446Strhodesvoid
253135446Strhodesisc_sockaddr_any(isc_sockaddr_t *sockaddr)
254135446Strhodes{
255135446Strhodes	memset(sockaddr, 0, sizeof(*sockaddr));
256135446Strhodes	sockaddr->type.sin.sin_family = AF_INET;
257135446Strhodes#ifdef ISC_PLATFORM_HAVESALEN
258135446Strhodes	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
259135446Strhodes#endif
260135446Strhodes	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
261135446Strhodes	sockaddr->type.sin.sin_port = 0;
262135446Strhodes	sockaddr->length = sizeof(sockaddr->type.sin);
263135446Strhodes	ISC_LINK_INIT(sockaddr, link);
264135446Strhodes}
265135446Strhodes
266135446Strhodesvoid
267135446Strhodesisc_sockaddr_any6(isc_sockaddr_t *sockaddr)
268135446Strhodes{
269135446Strhodes	memset(sockaddr, 0, sizeof(*sockaddr));
270135446Strhodes	sockaddr->type.sin6.sin6_family = AF_INET6;
271135446Strhodes#ifdef ISC_PLATFORM_HAVESALEN
272135446Strhodes	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
273135446Strhodes#endif
274135446Strhodes	sockaddr->type.sin6.sin6_addr = in6addr_any;
275135446Strhodes	sockaddr->type.sin6.sin6_port = 0;
276135446Strhodes	sockaddr->length = sizeof(sockaddr->type.sin6);
277135446Strhodes	ISC_LINK_INIT(sockaddr, link);
278135446Strhodes}
279135446Strhodes
280135446Strhodesvoid
281135446Strhodesisc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
282135446Strhodes		    in_port_t port)
283135446Strhodes{
284135446Strhodes	memset(sockaddr, 0, sizeof(*sockaddr));
285135446Strhodes	sockaddr->type.sin.sin_family = AF_INET;
286135446Strhodes#ifdef ISC_PLATFORM_HAVESALEN
287135446Strhodes	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
288135446Strhodes#endif
289135446Strhodes	sockaddr->type.sin.sin_addr = *ina;
290135446Strhodes	sockaddr->type.sin.sin_port = htons(port);
291135446Strhodes	sockaddr->length = sizeof(sockaddr->type.sin);
292135446Strhodes	ISC_LINK_INIT(sockaddr, link);
293135446Strhodes}
294135446Strhodes
295135446Strhodesvoid
296135446Strhodesisc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
297135446Strhodes     switch (pf) {
298135446Strhodes     case AF_INET:
299135446Strhodes	     isc_sockaddr_any(sockaddr);
300135446Strhodes	     break;
301135446Strhodes     case AF_INET6:
302135446Strhodes	     isc_sockaddr_any6(sockaddr);
303135446Strhodes	     break;
304135446Strhodes     default:
305135446Strhodes	     INSIST(0);
306135446Strhodes     }
307135446Strhodes}
308135446Strhodes
309135446Strhodesvoid
310135446Strhodesisc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
311135446Strhodes		     in_port_t port)
312135446Strhodes{
313135446Strhodes	memset(sockaddr, 0, sizeof(*sockaddr));
314135446Strhodes	sockaddr->type.sin6.sin6_family = AF_INET6;
315135446Strhodes#ifdef ISC_PLATFORM_HAVESALEN
316135446Strhodes	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
317135446Strhodes#endif
318135446Strhodes	sockaddr->type.sin6.sin6_addr = *ina6;
319135446Strhodes	sockaddr->type.sin6.sin6_port = htons(port);
320135446Strhodes	sockaddr->length = sizeof(sockaddr->type.sin6);
321135446Strhodes	ISC_LINK_INIT(sockaddr, link);
322135446Strhodes}
323135446Strhodes
324135446Strhodesvoid
325135446Strhodesisc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
326135446Strhodes		      in_port_t port)
327135446Strhodes{
328135446Strhodes	memset(sockaddr, 0, sizeof(*sockaddr));
329135446Strhodes	sockaddr->type.sin6.sin6_family = AF_INET6;
330135446Strhodes#ifdef ISC_PLATFORM_HAVESALEN
331135446Strhodes	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
332135446Strhodes#endif
333135446Strhodes	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
334135446Strhodes	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
335262706Serwin	memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
336135446Strhodes	sockaddr->type.sin6.sin6_port = htons(port);
337135446Strhodes	sockaddr->length = sizeof(sockaddr->type.sin6);
338135446Strhodes	ISC_LINK_INIT(sockaddr, link);
339135446Strhodes}
340135446Strhodes
341135446Strhodesint
342135446Strhodesisc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
343135446Strhodes
344135446Strhodes	/*
345135446Strhodes	 * Get the protocol family of 'sockaddr'.
346135446Strhodes	 */
347135446Strhodes
348135446Strhodes#if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
349135446Strhodes	/*
350135446Strhodes	 * Assume that PF_xxx == AF_xxx for all AF and PF.
351135446Strhodes	 */
352135446Strhodes	return (sockaddr->type.sa.sa_family);
353135446Strhodes#else
354135446Strhodes	switch (sockaddr->type.sa.sa_family) {
355135446Strhodes	case AF_INET:
356135446Strhodes		return (PF_INET);
357135446Strhodes	case AF_INET6:
358135446Strhodes		return (PF_INET6);
359135446Strhodes	default:
360135446Strhodes		FATAL_ERROR(__FILE__, __LINE__,
361135446Strhodes			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
362135446Strhodes					   ISC_MSG_UNKNOWNFAMILY,
363135446Strhodes					   "unknown address family: %d"),
364135446Strhodes			    (int)sockaddr->type.sa.sa_family);
365135446Strhodes	}
366135446Strhodes#endif
367135446Strhodes}
368135446Strhodes
369135446Strhodesvoid
370135446Strhodesisc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
371135446Strhodes		    in_port_t port)
372135446Strhodes{
373135446Strhodes	memset(sockaddr, 0, sizeof(*sockaddr));
374135446Strhodes	sockaddr->type.sin.sin_family = na->family;
375135446Strhodes	switch (na->family) {
376135446Strhodes	case AF_INET:
377135446Strhodes		sockaddr->length = sizeof(sockaddr->type.sin);
378135446Strhodes#ifdef ISC_PLATFORM_HAVESALEN
379135446Strhodes		sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
380135446Strhodes#endif
381135446Strhodes		sockaddr->type.sin.sin_addr = na->type.in;
382135446Strhodes		sockaddr->type.sin.sin_port = htons(port);
383135446Strhodes		break;
384135446Strhodes	case AF_INET6:
385135446Strhodes		sockaddr->length = sizeof(sockaddr->type.sin6);
386135446Strhodes#ifdef ISC_PLATFORM_HAVESALEN
387135446Strhodes		sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
388135446Strhodes#endif
389262706Serwin		memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
390135446Strhodes#ifdef ISC_PLATFORM_HAVESCOPEID
391135446Strhodes		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
392135446Strhodes#endif
393135446Strhodes		sockaddr->type.sin6.sin6_port = htons(port);
394135446Strhodes		break;
395224092Sdougb	default:
396224092Sdougb		INSIST(0);
397135446Strhodes	}
398135446Strhodes	ISC_LINK_INIT(sockaddr, link);
399135446Strhodes}
400135446Strhodes
401135446Strhodesvoid
402135446Strhodesisc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
403135446Strhodes	switch (sockaddr->type.sa.sa_family) {
404135446Strhodes	case AF_INET:
405135446Strhodes		sockaddr->type.sin.sin_port = htons(port);
406135446Strhodes		break;
407135446Strhodes	case AF_INET6:
408135446Strhodes		sockaddr->type.sin6.sin6_port = htons(port);
409135446Strhodes		break;
410135446Strhodes	default:
411135446Strhodes		FATAL_ERROR(__FILE__, __LINE__,
412135446Strhodes			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
413135446Strhodes					   ISC_MSG_UNKNOWNFAMILY,
414135446Strhodes					   "unknown address family: %d"),
415135446Strhodes			    (int)sockaddr->type.sa.sa_family);
416135446Strhodes	}
417135446Strhodes}
418135446Strhodes
419135446Strhodesin_port_t
420165071Sdougbisc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
421135446Strhodes	in_port_t port = 0;
422135446Strhodes
423135446Strhodes	switch (sockaddr->type.sa.sa_family) {
424135446Strhodes	case AF_INET:
425135446Strhodes		port = ntohs(sockaddr->type.sin.sin_port);
426135446Strhodes		break;
427135446Strhodes	case AF_INET6:
428135446Strhodes		port = ntohs(sockaddr->type.sin6.sin6_port);
429135446Strhodes		break;
430135446Strhodes	default:
431135446Strhodes		FATAL_ERROR(__FILE__, __LINE__,
432135446Strhodes			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
433135446Strhodes					   ISC_MSG_UNKNOWNFAMILY,
434135446Strhodes					   "unknown address family: %d"),
435135446Strhodes			    (int)sockaddr->type.sa.sa_family);
436135446Strhodes	}
437135446Strhodes
438135446Strhodes	return (port);
439135446Strhodes}
440135446Strhodes
441135446Strhodesisc_boolean_t
442165071Sdougbisc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
443135446Strhodes	isc_netaddr_t netaddr;
444135446Strhodes
445170222Sdougb	if (sockaddr->type.sa.sa_family == AF_INET ||
446170222Sdougb	    sockaddr->type.sa.sa_family == AF_INET6) {
447170222Sdougb		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
448170222Sdougb		return (isc_netaddr_ismulticast(&netaddr));
449170222Sdougb	}
450170222Sdougb	return (ISC_FALSE);
451135446Strhodes}
452135446Strhodes
453135446Strhodesisc_boolean_t
454165071Sdougbisc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
455135446Strhodes	isc_netaddr_t netaddr;
456135446Strhodes
457135446Strhodes	if (sockaddr->type.sa.sa_family == AF_INET) {
458135446Strhodes		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
459135446Strhodes		return (isc_netaddr_isexperimental(&netaddr));
460135446Strhodes	}
461135446Strhodes	return (ISC_FALSE);
462135446Strhodes}
463135446Strhodes
464135446Strhodesisc_boolean_t
465165071Sdougbisc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
466135446Strhodes	isc_netaddr_t netaddr;
467135446Strhodes
468135446Strhodes	if (sockaddr->type.sa.sa_family == AF_INET6) {
469135446Strhodes		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
470135446Strhodes		return (isc_netaddr_issitelocal(&netaddr));
471135446Strhodes	}
472135446Strhodes	return (ISC_FALSE);
473135446Strhodes}
474135446Strhodes
475135446Strhodesisc_boolean_t
476165071Sdougbisc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
477135446Strhodes	isc_netaddr_t netaddr;
478135446Strhodes
479135446Strhodes	if (sockaddr->type.sa.sa_family == AF_INET6) {
480135446Strhodes		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
481135446Strhodes		return (isc_netaddr_islinklocal(&netaddr));
482135446Strhodes	}
483135446Strhodes	return (ISC_FALSE);
484135446Strhodes}
485170222Sdougb
486170222Sdougbisc_result_t
487170222Sdougbisc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
488170222Sdougb#ifdef ISC_PLATFORM_HAVESYSUNH
489170222Sdougb	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
490170222Sdougb		return (ISC_R_NOSPACE);
491170222Sdougb	memset(sockaddr, 0, sizeof(*sockaddr));
492170222Sdougb	sockaddr->length = sizeof(sockaddr->type.sunix);
493170222Sdougb	sockaddr->type.sunix.sun_family = AF_UNIX;
494170222Sdougb#ifdef ISC_PLATFORM_HAVESALEN
495170222Sdougb	sockaddr->type.sunix.sun_len =
496170222Sdougb			(unsigned char)sizeof(sockaddr->type.sunix);
497170222Sdougb#endif
498170222Sdougb	strcpy(sockaddr->type.sunix.sun_path, path);
499170222Sdougb	return (ISC_R_SUCCESS);
500170222Sdougb#else
501170222Sdougb	UNUSED(sockaddr);
502170222Sdougb	UNUSED(path);
503170222Sdougb	return (ISC_R_NOTIMPLEMENTED);
504170222Sdougb#endif
505170222Sdougb}
506