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