xref: /netbsd-src/external/bsd/ntp/dist/libntp/lib/isc/sockaddr.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: sockaddr.c,v 1.2 2024/08/18 20:47:14 christos Exp $	*/
2897be3a4Schristos 
3897be3a4Schristos /*
4897be3a4Schristos  * Copyright (C) 2004-2007, 2010-2012  Internet Systems Consortium, Inc. ("ISC")
5897be3a4Schristos  * Copyright (C) 1999-2003  Internet Software Consortium.
6897be3a4Schristos  *
7897be3a4Schristos  * Permission to use, copy, modify, and/or distribute this software for any
8897be3a4Schristos  * purpose with or without fee is hereby granted, provided that the above
9897be3a4Schristos  * copyright notice and this permission notice appear in all copies.
10897be3a4Schristos  *
11897be3a4Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12897be3a4Schristos  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13897be3a4Schristos  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14897be3a4Schristos  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15897be3a4Schristos  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16897be3a4Schristos  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17897be3a4Schristos  * PERFORMANCE OF THIS SOFTWARE.
18897be3a4Schristos  */
19897be3a4Schristos 
20897be3a4Schristos /* Id */
21897be3a4Schristos 
22897be3a4Schristos /*! \file */
23897be3a4Schristos 
24897be3a4Schristos #include <config.h>
25897be3a4Schristos 
26897be3a4Schristos #include <stdio.h>
27897be3a4Schristos 
28897be3a4Schristos #include <isc/buffer.h>
29897be3a4Schristos #include <isc/hash.h>
30897be3a4Schristos #include <isc/msgs.h>
31897be3a4Schristos #include <isc/netaddr.h>
32897be3a4Schristos #include <isc/print.h>
33897be3a4Schristos #include <isc/region.h>
34897be3a4Schristos #include <isc/sockaddr.h>
35897be3a4Schristos #include <isc/string.h>
36897be3a4Schristos #include <isc/util.h>
37897be3a4Schristos 
38897be3a4Schristos isc_boolean_t
39897be3a4Schristos isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
40897be3a4Schristos 	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
41897be3a4Schristos 					   ISC_SOCKADDR_CMPPORT|
42897be3a4Schristos 					   ISC_SOCKADDR_CMPSCOPE));
43897be3a4Schristos }
44897be3a4Schristos 
45897be3a4Schristos isc_boolean_t
46897be3a4Schristos isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
47897be3a4Schristos 	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
48897be3a4Schristos 					   ISC_SOCKADDR_CMPSCOPE));
49897be3a4Schristos }
50897be3a4Schristos 
51897be3a4Schristos isc_boolean_t
52897be3a4Schristos isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
53897be3a4Schristos 		     unsigned int flags)
54897be3a4Schristos {
55897be3a4Schristos 	REQUIRE(a != NULL && b != NULL);
56897be3a4Schristos 
57897be3a4Schristos 	if (a->length != b->length)
58897be3a4Schristos 		return (ISC_FALSE);
59897be3a4Schristos 
60897be3a4Schristos 	/*
61897be3a4Schristos 	 * We don't just memcmp because the sin_zero field isn't always
62897be3a4Schristos 	 * zero.
63897be3a4Schristos 	 */
64897be3a4Schristos 
65897be3a4Schristos 	if (a->type.sa.sa_family != b->type.sa.sa_family)
66897be3a4Schristos 		return (ISC_FALSE);
67897be3a4Schristos 	switch (a->type.sa.sa_family) {
68897be3a4Schristos 	case AF_INET:
69897be3a4Schristos 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
70897be3a4Schristos 		    memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
71897be3a4Schristos 			   sizeof(a->type.sin.sin_addr)) != 0)
72897be3a4Schristos 			return (ISC_FALSE);
73897be3a4Schristos 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
74897be3a4Schristos 		    a->type.sin.sin_port != b->type.sin.sin_port)
75897be3a4Schristos 			return (ISC_FALSE);
76897be3a4Schristos 		break;
77897be3a4Schristos 	case AF_INET6:
78897be3a4Schristos 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
79897be3a4Schristos 		    memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
80897be3a4Schristos 			   sizeof(a->type.sin6.sin6_addr)) != 0)
81897be3a4Schristos 			return (ISC_FALSE);
82897be3a4Schristos #ifdef ISC_PLATFORM_HAVESCOPEID
83897be3a4Schristos 		/*
84897be3a4Schristos 		 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
85897be3a4Schristos 		 * ISC_FALSE if one of the scopes in zero.
86897be3a4Schristos 		 */
87897be3a4Schristos 		if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
88897be3a4Schristos 		    a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
89897be3a4Schristos 		    ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
90897be3a4Schristos 		      (a->type.sin6.sin6_scope_id != 0 &&
91897be3a4Schristos 		       b->type.sin6.sin6_scope_id != 0)))
92897be3a4Schristos 			return (ISC_FALSE);
93897be3a4Schristos #endif
94897be3a4Schristos 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
95897be3a4Schristos 		    a->type.sin6.sin6_port != b->type.sin6.sin6_port)
96897be3a4Schristos 			return (ISC_FALSE);
97897be3a4Schristos 		break;
98897be3a4Schristos 	default:
99897be3a4Schristos 		if (memcmp(&a->type, &b->type, a->length) != 0)
100897be3a4Schristos 			return (ISC_FALSE);
101897be3a4Schristos 	}
102897be3a4Schristos 	return (ISC_TRUE);
103897be3a4Schristos }
104897be3a4Schristos 
105897be3a4Schristos isc_boolean_t
106897be3a4Schristos isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
107897be3a4Schristos 			  unsigned int prefixlen)
108897be3a4Schristos {
109897be3a4Schristos 	isc_netaddr_t na, nb;
110897be3a4Schristos 	isc_netaddr_fromsockaddr(&na, a);
111897be3a4Schristos 	isc_netaddr_fromsockaddr(&nb, b);
112897be3a4Schristos 	return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
113897be3a4Schristos }
114897be3a4Schristos 
115897be3a4Schristos isc_result_t
116897be3a4Schristos isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
117897be3a4Schristos 	isc_result_t result;
118897be3a4Schristos 	isc_netaddr_t netaddr;
119897be3a4Schristos 	char pbuf[sizeof("65000")];
120897be3a4Schristos 	unsigned int plen;
121897be3a4Schristos 	isc_region_t avail;
122897be3a4Schristos 
123897be3a4Schristos 	REQUIRE(sockaddr != NULL);
124897be3a4Schristos 
125897be3a4Schristos 	/*
126897be3a4Schristos 	 * Do the port first, giving us the opportunity to check for
127897be3a4Schristos 	 * unsupported address families before calling
128897be3a4Schristos 	 * isc_netaddr_fromsockaddr().
129897be3a4Schristos 	 */
130897be3a4Schristos 	switch (sockaddr->type.sa.sa_family) {
131897be3a4Schristos 	case AF_INET:
132897be3a4Schristos 		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
133897be3a4Schristos 		break;
134897be3a4Schristos 	case AF_INET6:
135897be3a4Schristos 		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
136897be3a4Schristos 		break;
137897be3a4Schristos #ifdef ISC_PLAFORM_HAVESYSUNH
138897be3a4Schristos 	case AF_UNIX:
139897be3a4Schristos 		plen = (unsigned int)strlen(sockaddr->type.sunix.sun_path);
140897be3a4Schristos 		if (plen >= isc_buffer_availablelength(target))
141897be3a4Schristos 			return (ISC_R_NOSPACE);
142897be3a4Schristos 
143897be3a4Schristos 		isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
144897be3a4Schristos 
145897be3a4Schristos 		/*
146897be3a4Schristos 		 * Null terminate after used region.
147897be3a4Schristos 		 */
148897be3a4Schristos 		isc_buffer_availableregion(target, &avail);
149897be3a4Schristos 		INSIST(avail.length >= 1);
150897be3a4Schristos 		avail.base[0] = '\0';
151897be3a4Schristos 
152897be3a4Schristos 		return (ISC_R_SUCCESS);
153897be3a4Schristos #endif
154897be3a4Schristos 	default:
155897be3a4Schristos 		return (ISC_R_FAILURE);
156897be3a4Schristos 	}
157897be3a4Schristos 
158897be3a4Schristos 	plen = (unsigned int)strlen(pbuf);
159897be3a4Schristos 	INSIST(plen < sizeof(pbuf));
160897be3a4Schristos 
161897be3a4Schristos 	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
162897be3a4Schristos 	result = isc_netaddr_totext(&netaddr, target);
163897be3a4Schristos 	if (result != ISC_R_SUCCESS)
164897be3a4Schristos 		return (result);
165897be3a4Schristos 
166897be3a4Schristos 	if (1 + plen + 1 > isc_buffer_availablelength(target))
167897be3a4Schristos 		return (ISC_R_NOSPACE);
168897be3a4Schristos 
169897be3a4Schristos 	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
170897be3a4Schristos 	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
171897be3a4Schristos 
172897be3a4Schristos 	/*
173897be3a4Schristos 	 * Null terminate after used region.
174897be3a4Schristos 	 */
175897be3a4Schristos 	isc_buffer_availableregion(target, &avail);
176897be3a4Schristos 	INSIST(avail.length >= 1);
177897be3a4Schristos 	avail.base[0] = '\0';
178897be3a4Schristos 
179897be3a4Schristos 	return (ISC_R_SUCCESS);
180897be3a4Schristos }
181897be3a4Schristos 
182897be3a4Schristos void
183897be3a4Schristos isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
184897be3a4Schristos 	isc_result_t result;
185897be3a4Schristos 	isc_buffer_t buf;
186897be3a4Schristos 
187897be3a4Schristos 	if (size == 0U)
188897be3a4Schristos 		return;
189897be3a4Schristos 
190897be3a4Schristos 	isc_buffer_init(&buf, array, size);
191897be3a4Schristos 	result = isc_sockaddr_totext(sa, &buf);
192897be3a4Schristos 	if (result != ISC_R_SUCCESS) {
193897be3a4Schristos 		/*
194897be3a4Schristos 		 * The message is the same as in netaddr.c.
195897be3a4Schristos 		 */
196897be3a4Schristos 		snprintf(array, size,
197897be3a4Schristos 			 "<%s %u>",
198897be3a4Schristos 			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
199897be3a4Schristos 					ISC_MSG_UNKNOWNADDR,
200897be3a4Schristos 					"unknown address, family"),
201897be3a4Schristos 			 sa->type.sa.sa_family);
202897be3a4Schristos 		array[size - 1] = '\0';
203897be3a4Schristos 	}
204897be3a4Schristos }
205897be3a4Schristos 
206897be3a4Schristos unsigned int
207897be3a4Schristos isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
208897be3a4Schristos 	unsigned int length = 0;
209897be3a4Schristos 	const unsigned char *s = NULL;
210897be3a4Schristos 	unsigned int h = 0;
211897be3a4Schristos 	unsigned int g;
212897be3a4Schristos 	unsigned int p = 0;
213897be3a4Schristos 	const struct in6_addr *in6;
214897be3a4Schristos 
215897be3a4Schristos 	REQUIRE(sockaddr != NULL);
216897be3a4Schristos 
217897be3a4Schristos 	switch (sockaddr->type.sa.sa_family) {
218897be3a4Schristos 	case AF_INET:
219897be3a4Schristos 		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
220897be3a4Schristos 		p = ntohs(sockaddr->type.sin.sin_port);
221897be3a4Schristos 		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
222897be3a4Schristos 		break;
223897be3a4Schristos 	case AF_INET6:
224897be3a4Schristos 		in6 = &sockaddr->type.sin6.sin6_addr;
225897be3a4Schristos 		if (IN6_IS_ADDR_V4MAPPED(in6)) {
226897be3a4Schristos 			s = (const unsigned char *)&in6 + 12;
227897be3a4Schristos 			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
228897be3a4Schristos 		} else {
229897be3a4Schristos 			s = (const unsigned char *)in6;
230897be3a4Schristos 			length = sizeof(sockaddr->type.sin6.sin6_addr);
231897be3a4Schristos 		}
232897be3a4Schristos 		p = ntohs(sockaddr->type.sin6.sin6_port);
233897be3a4Schristos 		break;
234897be3a4Schristos 	default:
235897be3a4Schristos 		UNEXPECTED_ERROR(__FILE__, __LINE__,
236897be3a4Schristos 				 "%s: %d",
237897be3a4Schristos 				 isc_msgcat_get(isc_msgcat,
238897be3a4Schristos 						ISC_MSGSET_SOCKADDR,
239897be3a4Schristos 						ISC_MSG_UNKNOWNFAMILY,
240897be3a4Schristos 						"unknown address family"),
241897be3a4Schristos 					     (int)sockaddr->type.sa.sa_family);
242897be3a4Schristos 		s = (const unsigned char *)&sockaddr->type;
243897be3a4Schristos 		length = sockaddr->length;
244897be3a4Schristos 		p = 0;
245897be3a4Schristos 	}
246897be3a4Schristos 
247897be3a4Schristos 	h = isc_hash_calc(s, length, ISC_TRUE);
248897be3a4Schristos 	if (!address_only) {
249897be3a4Schristos 		g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
250897be3a4Schristos 				  ISC_TRUE);
251897be3a4Schristos 		h = h ^ g; /* XXX: we should concatenate h and p first */
252897be3a4Schristos 	}
253897be3a4Schristos 
254897be3a4Schristos 	return (h);
255897be3a4Schristos }
256897be3a4Schristos 
257897be3a4Schristos void
258897be3a4Schristos isc_sockaddr_any(isc_sockaddr_t *sockaddr)
259897be3a4Schristos {
260897be3a4Schristos 	memset(sockaddr, 0, sizeof(*sockaddr));
261897be3a4Schristos 	sockaddr->type.sin.sin_family = AF_INET;
262897be3a4Schristos #ifdef ISC_PLATFORM_HAVESALEN
263897be3a4Schristos 	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
264897be3a4Schristos #endif
265897be3a4Schristos 	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
266897be3a4Schristos 	sockaddr->type.sin.sin_port = 0;
267897be3a4Schristos 	sockaddr->length = sizeof(sockaddr->type.sin);
268897be3a4Schristos 	ISC_LINK_INIT(sockaddr, link);
269897be3a4Schristos }
270897be3a4Schristos 
271897be3a4Schristos void
272897be3a4Schristos isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
273897be3a4Schristos {
274897be3a4Schristos 	memset(sockaddr, 0, sizeof(*sockaddr));
275897be3a4Schristos 	sockaddr->type.sin6.sin6_family = AF_INET6;
276897be3a4Schristos #ifdef ISC_PLATFORM_HAVESALEN
277897be3a4Schristos 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
278897be3a4Schristos #endif
279897be3a4Schristos 	sockaddr->type.sin6.sin6_addr = in6addr_any;
280897be3a4Schristos 	sockaddr->type.sin6.sin6_port = 0;
281897be3a4Schristos 	sockaddr->length = sizeof(sockaddr->type.sin6);
282897be3a4Schristos 	ISC_LINK_INIT(sockaddr, link);
283897be3a4Schristos }
284897be3a4Schristos 
285897be3a4Schristos void
286897be3a4Schristos isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
287897be3a4Schristos 		    in_port_t port)
288897be3a4Schristos {
289897be3a4Schristos 	memset(sockaddr, 0, sizeof(*sockaddr));
290897be3a4Schristos 	sockaddr->type.sin.sin_family = AF_INET;
291897be3a4Schristos #ifdef ISC_PLATFORM_HAVESALEN
292897be3a4Schristos 	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
293897be3a4Schristos #endif
294897be3a4Schristos 	sockaddr->type.sin.sin_addr = *ina;
295897be3a4Schristos 	sockaddr->type.sin.sin_port = htons(port);
296897be3a4Schristos 	sockaddr->length = sizeof(sockaddr->type.sin);
297897be3a4Schristos 	ISC_LINK_INIT(sockaddr, link);
298897be3a4Schristos }
299897be3a4Schristos 
300897be3a4Schristos void
301897be3a4Schristos isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
302897be3a4Schristos      switch (pf) {
303897be3a4Schristos      case AF_INET:
304897be3a4Schristos 	     isc_sockaddr_any(sockaddr);
305897be3a4Schristos 	     break;
306897be3a4Schristos      case AF_INET6:
307897be3a4Schristos 	     isc_sockaddr_any6(sockaddr);
308897be3a4Schristos 	     break;
309897be3a4Schristos      default:
310897be3a4Schristos 	     INSIST(0);
311897be3a4Schristos      }
312897be3a4Schristos }
313897be3a4Schristos 
314897be3a4Schristos void
315897be3a4Schristos isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
316897be3a4Schristos 		     in_port_t port)
317897be3a4Schristos {
318897be3a4Schristos 	memset(sockaddr, 0, sizeof(*sockaddr));
319897be3a4Schristos 	sockaddr->type.sin6.sin6_family = AF_INET6;
320897be3a4Schristos #ifdef ISC_PLATFORM_HAVESALEN
321897be3a4Schristos 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
322897be3a4Schristos #endif
323897be3a4Schristos 	sockaddr->type.sin6.sin6_addr = *ina6;
324897be3a4Schristos 	sockaddr->type.sin6.sin6_port = htons(port);
325897be3a4Schristos 	sockaddr->length = sizeof(sockaddr->type.sin6);
326897be3a4Schristos 	ISC_LINK_INIT(sockaddr, link);
327897be3a4Schristos }
328897be3a4Schristos 
329897be3a4Schristos void
330897be3a4Schristos isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
331897be3a4Schristos 		      in_port_t port)
332897be3a4Schristos {
333897be3a4Schristos 	memset(sockaddr, 0, sizeof(*sockaddr));
334897be3a4Schristos 	sockaddr->type.sin6.sin6_family = AF_INET6;
335897be3a4Schristos #ifdef ISC_PLATFORM_HAVESALEN
336897be3a4Schristos 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
337897be3a4Schristos #endif
338897be3a4Schristos 	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
339897be3a4Schristos 	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
340897be3a4Schristos 	memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
341897be3a4Schristos 	sockaddr->type.sin6.sin6_port = htons(port);
342897be3a4Schristos 	sockaddr->length = sizeof(sockaddr->type.sin6);
343897be3a4Schristos 	ISC_LINK_INIT(sockaddr, link);
344897be3a4Schristos }
345897be3a4Schristos 
346897be3a4Schristos int
347897be3a4Schristos isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
348897be3a4Schristos 
349897be3a4Schristos 	/*
350897be3a4Schristos 	 * Get the protocol family of 'sockaddr'.
351897be3a4Schristos 	 */
352897be3a4Schristos 
353897be3a4Schristos #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
354897be3a4Schristos 	/*
355897be3a4Schristos 	 * Assume that PF_xxx == AF_xxx for all AF and PF.
356897be3a4Schristos 	 */
357897be3a4Schristos 	return (sockaddr->type.sa.sa_family);
358897be3a4Schristos #else
359897be3a4Schristos 	switch (sockaddr->type.sa.sa_family) {
360897be3a4Schristos 	case AF_INET:
361897be3a4Schristos 		return (PF_INET);
362897be3a4Schristos 	case AF_INET6:
363897be3a4Schristos 		return (PF_INET6);
364897be3a4Schristos 	default:
365897be3a4Schristos 		FATAL_ERROR(__FILE__, __LINE__,
366897be3a4Schristos 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
367897be3a4Schristos 					   ISC_MSG_UNKNOWNFAMILY,
368897be3a4Schristos 					   "unknown address family: %d"),
369897be3a4Schristos 			    (int)sockaddr->type.sa.sa_family);
370897be3a4Schristos 	}
371897be3a4Schristos #endif
372897be3a4Schristos }
373897be3a4Schristos 
374897be3a4Schristos void
375897be3a4Schristos isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
376897be3a4Schristos 		    in_port_t port)
377897be3a4Schristos {
378897be3a4Schristos 	memset(sockaddr, 0, sizeof(*sockaddr));
379897be3a4Schristos 	sockaddr->type.sin.sin_family = (short)na->family;
380897be3a4Schristos 	switch (na->family) {
381897be3a4Schristos 	case AF_INET:
382897be3a4Schristos 		sockaddr->length = sizeof(sockaddr->type.sin);
383897be3a4Schristos #ifdef ISC_PLATFORM_HAVESALEN
384897be3a4Schristos 		sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
385897be3a4Schristos #endif
386897be3a4Schristos 		sockaddr->type.sin.sin_addr = na->type.in;
387897be3a4Schristos 		sockaddr->type.sin.sin_port = htons(port);
388897be3a4Schristos 		break;
389897be3a4Schristos 	case AF_INET6:
390897be3a4Schristos 		sockaddr->length = sizeof(sockaddr->type.sin6);
391897be3a4Schristos #ifdef ISC_PLATFORM_HAVESALEN
392897be3a4Schristos 		sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
393897be3a4Schristos #endif
394897be3a4Schristos 		memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
395897be3a4Schristos #ifdef ISC_PLATFORM_HAVESCOPEID
396897be3a4Schristos 		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
397897be3a4Schristos #endif
398897be3a4Schristos 		sockaddr->type.sin6.sin6_port = htons(port);
399897be3a4Schristos 		break;
400897be3a4Schristos 	default:
401897be3a4Schristos 		INSIST(0);
402897be3a4Schristos 	}
403897be3a4Schristos 	ISC_LINK_INIT(sockaddr, link);
404897be3a4Schristos }
405897be3a4Schristos 
406897be3a4Schristos void
407897be3a4Schristos isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
408897be3a4Schristos 	switch (sockaddr->type.sa.sa_family) {
409897be3a4Schristos 	case AF_INET:
410897be3a4Schristos 		sockaddr->type.sin.sin_port = htons(port);
411897be3a4Schristos 		break;
412897be3a4Schristos 	case AF_INET6:
413897be3a4Schristos 		sockaddr->type.sin6.sin6_port = htons(port);
414897be3a4Schristos 		break;
415897be3a4Schristos 	default:
416897be3a4Schristos 		FATAL_ERROR(__FILE__, __LINE__,
417897be3a4Schristos 			    "%s: %d",
418897be3a4Schristos 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
419897be3a4Schristos 					   ISC_MSG_UNKNOWNFAMILY,
420897be3a4Schristos 					   "unknown address family"),
421897be3a4Schristos 			    (int)sockaddr->type.sa.sa_family);
422897be3a4Schristos 	}
423897be3a4Schristos }
424897be3a4Schristos 
425897be3a4Schristos in_port_t
426897be3a4Schristos isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
427897be3a4Schristos 	in_port_t port = 0;
428897be3a4Schristos 
429897be3a4Schristos 	switch (sockaddr->type.sa.sa_family) {
430897be3a4Schristos 	case AF_INET:
431897be3a4Schristos 		port = ntohs(sockaddr->type.sin.sin_port);
432897be3a4Schristos 		break;
433897be3a4Schristos 	case AF_INET6:
434897be3a4Schristos 		port = ntohs(sockaddr->type.sin6.sin6_port);
435897be3a4Schristos 		break;
436897be3a4Schristos 	default:
437897be3a4Schristos 		FATAL_ERROR(__FILE__, __LINE__,
438897be3a4Schristos 			    "%s: %d",
439897be3a4Schristos 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
440897be3a4Schristos 					   ISC_MSG_UNKNOWNFAMILY,
441897be3a4Schristos 					   "unknown address family"),
442897be3a4Schristos 			    (int)sockaddr->type.sa.sa_family);
443897be3a4Schristos 	}
444897be3a4Schristos 
445897be3a4Schristos 	return (port);
446897be3a4Schristos }
447897be3a4Schristos 
448897be3a4Schristos isc_boolean_t
449897be3a4Schristos isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
450897be3a4Schristos 	isc_netaddr_t netaddr;
451897be3a4Schristos 
452897be3a4Schristos 	if (sockaddr->type.sa.sa_family == AF_INET ||
453897be3a4Schristos 	    sockaddr->type.sa.sa_family == AF_INET6) {
454897be3a4Schristos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
455897be3a4Schristos 		return (isc_netaddr_ismulticast(&netaddr));
456897be3a4Schristos 	}
457897be3a4Schristos 	return (ISC_FALSE);
458897be3a4Schristos }
459897be3a4Schristos 
460897be3a4Schristos isc_boolean_t
461897be3a4Schristos isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
462897be3a4Schristos 	isc_netaddr_t netaddr;
463897be3a4Schristos 
464897be3a4Schristos 	if (sockaddr->type.sa.sa_family == AF_INET) {
465897be3a4Schristos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
466897be3a4Schristos 		return (isc_netaddr_isexperimental(&netaddr));
467897be3a4Schristos 	}
468897be3a4Schristos 	return (ISC_FALSE);
469897be3a4Schristos }
470897be3a4Schristos 
471897be3a4Schristos isc_boolean_t
472897be3a4Schristos isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
473897be3a4Schristos 	isc_netaddr_t netaddr;
474897be3a4Schristos 
475897be3a4Schristos 	if (sockaddr->type.sa.sa_family == AF_INET6) {
476897be3a4Schristos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
477897be3a4Schristos 		return (isc_netaddr_issitelocal(&netaddr));
478897be3a4Schristos 	}
479897be3a4Schristos 	return (ISC_FALSE);
480897be3a4Schristos }
481897be3a4Schristos 
482897be3a4Schristos isc_boolean_t
483897be3a4Schristos isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
484897be3a4Schristos 	isc_netaddr_t netaddr;
485897be3a4Schristos 
486897be3a4Schristos 	if (sockaddr->type.sa.sa_family == AF_INET6) {
487897be3a4Schristos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
488897be3a4Schristos 		return (isc_netaddr_islinklocal(&netaddr));
489897be3a4Schristos 	}
490897be3a4Schristos 	return (ISC_FALSE);
491897be3a4Schristos }
492897be3a4Schristos 
493897be3a4Schristos isc_result_t
494897be3a4Schristos isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
495897be3a4Schristos #ifdef ISC_PLATFORM_HAVESYSUNH
496897be3a4Schristos 	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
497897be3a4Schristos 		return (ISC_R_NOSPACE);
498897be3a4Schristos 	memset(sockaddr, 0, sizeof(*sockaddr));
499897be3a4Schristos 	sockaddr->length = sizeof(sockaddr->type.sunix);
500897be3a4Schristos 	sockaddr->type.sunix.sun_family = AF_UNIX;
501897be3a4Schristos #ifdef ISC_PLATFORM_HAVESALEN
502897be3a4Schristos 	sockaddr->type.sunix.sun_len =
503897be3a4Schristos 			(unsigned char)sizeof(sockaddr->type.sunix);
504897be3a4Schristos #endif
505897be3a4Schristos 	strcpy(sockaddr->type.sunix.sun_path, path);
506897be3a4Schristos 	return (ISC_R_SUCCESS);
507897be3a4Schristos #else
508897be3a4Schristos 	UNUSED(sockaddr);
509897be3a4Schristos 	UNUSED(path);
510897be3a4Schristos 	return (ISC_R_NOTIMPLEMENTED);
511897be3a4Schristos #endif
512897be3a4Schristos }
513