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