1/*	$NetBSD: sockaddr.c,v 1.11 2024/02/21 22:52:29 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 <stdbool.h>
19#include <stdio.h>
20
21#include <isc/buffer.h>
22#include <isc/hash.h>
23#include <isc/netaddr.h>
24#include <isc/print.h>
25#include <isc/region.h>
26#include <isc/sockaddr.h>
27#include <isc/string.h>
28#include <isc/util.h>
29
30bool
31isc_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
38bool
39isc_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
44bool
45isc_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
108bool
109isc_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
117isc_result_t
118isc_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	case AF_UNIX:
142		plen = strlen(sockaddr->type.sunix.sun_path);
143		if (plen >= isc_buffer_availablelength(target)) {
144			return (ISC_R_NOSPACE);
145		}
146
147		isc_buffer_putmem(
148			target,
149			(const unsigned char *)sockaddr->type.sunix.sun_path,
150			plen);
151
152		/*
153		 * Null terminate after used region.
154		 */
155		isc_buffer_availableregion(target, &avail);
156		INSIST(avail.length >= 1);
157		avail.base[0] = '\0';
158
159		return (ISC_R_SUCCESS);
160	default:
161		return (ISC_R_FAILURE);
162	}
163
164	plen = strlen(pbuf);
165	INSIST(plen < sizeof(pbuf));
166
167	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
168	result = isc_netaddr_totext(&netaddr, target);
169	if (result != ISC_R_SUCCESS) {
170		return (result);
171	}
172
173	if (1 + plen + 1 > isc_buffer_availablelength(target)) {
174		return (ISC_R_NOSPACE);
175	}
176
177	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
178	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
179
180	/*
181	 * Null terminate after used region.
182	 */
183	isc_buffer_availableregion(target, &avail);
184	INSIST(avail.length >= 1);
185	avail.base[0] = '\0';
186
187	return (ISC_R_SUCCESS);
188}
189
190void
191isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
192	isc_result_t result;
193	isc_buffer_t buf;
194
195	if (size == 0U) {
196		return;
197	}
198
199	isc_buffer_init(&buf, array, size);
200	result = isc_sockaddr_totext(sa, &buf);
201	if (result != ISC_R_SUCCESS) {
202		/*
203		 * The message is the same as in netaddr.c.
204		 */
205		snprintf(array, size, "<unknown address, family %u>",
206			 sa->type.sa.sa_family);
207		array[size - 1] = '\0';
208	}
209}
210
211unsigned int
212isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only) {
213	unsigned int length = 0;
214	const unsigned char *s = NULL;
215	unsigned int h = 0;
216	unsigned int p = 0;
217	const struct in6_addr *in6;
218
219	REQUIRE(sockaddr != NULL);
220
221	switch (sockaddr->type.sa.sa_family) {
222	case AF_INET:
223		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
224		p = ntohs(sockaddr->type.sin.sin_port);
225		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
226		break;
227	case AF_INET6:
228		in6 = &sockaddr->type.sin6.sin6_addr;
229		s = (const unsigned char *)in6;
230		if (IN6_IS_ADDR_V4MAPPED(in6)) {
231			s += 12;
232			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
233		} else {
234			length = sizeof(sockaddr->type.sin6.sin6_addr);
235		}
236		p = ntohs(sockaddr->type.sin6.sin6_port);
237		break;
238	default:
239		UNEXPECTED_ERROR("unknown address family: %d",
240				 (int)sockaddr->type.sa.sa_family);
241		s = (const unsigned char *)&sockaddr->type;
242		length = sockaddr->length;
243		p = 0;
244	}
245
246	uint8_t buf[sizeof(struct sockaddr_storage) + sizeof(p)];
247	memmove(buf, s, length);
248	if (!address_only) {
249		memmove(buf + length, &p, sizeof(p));
250		h = isc_hash_function(buf, length + sizeof(p), true);
251	} else {
252		h = isc_hash_function(buf, length, true);
253	}
254
255	return (h);
256}
257
258void
259isc_sockaddr_any(isc_sockaddr_t *sockaddr) {
260	memset(sockaddr, 0, sizeof(*sockaddr));
261	sockaddr->type.sin.sin_family = AF_INET;
262	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
263	sockaddr->type.sin.sin_port = 0;
264	sockaddr->length = sizeof(sockaddr->type.sin);
265	ISC_LINK_INIT(sockaddr, link);
266}
267
268void
269isc_sockaddr_any6(isc_sockaddr_t *sockaddr) {
270	memset(sockaddr, 0, sizeof(*sockaddr));
271	sockaddr->type.sin6.sin6_family = AF_INET6;
272	sockaddr->type.sin6.sin6_addr = in6addr_any;
273	sockaddr->type.sin6.sin6_port = 0;
274	sockaddr->length = sizeof(sockaddr->type.sin6);
275	ISC_LINK_INIT(sockaddr, link);
276}
277
278void
279isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
280		    in_port_t port) {
281	memset(sockaddr, 0, sizeof(*sockaddr));
282	sockaddr->type.sin.sin_family = AF_INET;
283	sockaddr->type.sin.sin_addr = *ina;
284	sockaddr->type.sin.sin_port = htons(port);
285	sockaddr->length = sizeof(sockaddr->type.sin);
286	ISC_LINK_INIT(sockaddr, link);
287}
288
289void
290isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
291	switch (pf) {
292	case AF_INET:
293		isc_sockaddr_any(sockaddr);
294		break;
295	case AF_INET6:
296		isc_sockaddr_any6(sockaddr);
297		break;
298	default:
299		UNREACHABLE();
300	}
301}
302
303void
304isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
305		     in_port_t port) {
306	memset(sockaddr, 0, sizeof(*sockaddr));
307	sockaddr->type.sin6.sin6_family = AF_INET6;
308	sockaddr->type.sin6.sin6_addr = *ina6;
309	sockaddr->type.sin6.sin6_port = htons(port);
310	sockaddr->length = sizeof(sockaddr->type.sin6);
311	ISC_LINK_INIT(sockaddr, link);
312}
313
314void
315isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
316		      in_port_t port) {
317	memset(sockaddr, 0, sizeof(*sockaddr));
318	sockaddr->type.sin6.sin6_family = AF_INET6;
319	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
320	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
321	memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
322	sockaddr->type.sin6.sin6_port = htons(port);
323	sockaddr->length = sizeof(sockaddr->type.sin6);
324	ISC_LINK_INIT(sockaddr, link);
325}
326
327int
328isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
329	/*
330	 * Get the protocol family of 'sockaddr'.
331	 */
332
333#if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
334	/*
335	 * Assume that PF_xxx == AF_xxx for all AF and PF.
336	 */
337	return (sockaddr->type.sa.sa_family);
338#else  /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */
339	switch (sockaddr->type.sa.sa_family) {
340	case AF_INET:
341		return (PF_INET);
342	case AF_INET6:
343		return (PF_INET6);
344	default:
345		FATAL_ERROR("unknown address family: %d",
346			    (int)sockaddr->type.sa.sa_family);
347	}
348#endif /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */
349}
350
351void
352isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
353			 in_port_t port) {
354	memset(sockaddr, 0, sizeof(*sockaddr));
355	sockaddr->type.sin.sin_family = na->family;
356	switch (na->family) {
357	case AF_INET:
358		sockaddr->length = sizeof(sockaddr->type.sin);
359		sockaddr->type.sin.sin_addr = na->type.in;
360		sockaddr->type.sin.sin_port = htons(port);
361		break;
362	case AF_INET6:
363		sockaddr->length = sizeof(sockaddr->type.sin6);
364		memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
365		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
366		sockaddr->type.sin6.sin6_port = htons(port);
367		break;
368	default:
369		UNREACHABLE();
370	}
371	ISC_LINK_INIT(sockaddr, link);
372}
373
374void
375isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
376	switch (sockaddr->type.sa.sa_family) {
377	case AF_INET:
378		sockaddr->type.sin.sin_port = htons(port);
379		break;
380	case AF_INET6:
381		sockaddr->type.sin6.sin6_port = htons(port);
382		break;
383	default:
384		FATAL_ERROR("unknown address family: %d",
385			    (int)sockaddr->type.sa.sa_family);
386	}
387}
388
389in_port_t
390isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
391	in_port_t port = 0;
392
393	switch (sockaddr->type.sa.sa_family) {
394	case AF_INET:
395		port = ntohs(sockaddr->type.sin.sin_port);
396		break;
397	case AF_INET6:
398		port = ntohs(sockaddr->type.sin6.sin6_port);
399		break;
400	default:
401		FATAL_ERROR("unknown address family: %d",
402			    (int)sockaddr->type.sa.sa_family);
403	}
404
405	return (port);
406}
407
408bool
409isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
410	isc_netaddr_t netaddr;
411
412	if (sockaddr->type.sa.sa_family == AF_INET ||
413	    sockaddr->type.sa.sa_family == AF_INET6)
414	{
415		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
416		return (isc_netaddr_ismulticast(&netaddr));
417	}
418	return (false);
419}
420
421bool
422isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
423	isc_netaddr_t netaddr;
424
425	if (sockaddr->type.sa.sa_family == AF_INET) {
426		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
427		return (isc_netaddr_isexperimental(&netaddr));
428	}
429	return (false);
430}
431
432bool
433isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
434	isc_netaddr_t netaddr;
435
436	if (sockaddr->type.sa.sa_family == AF_INET6) {
437		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
438		return (isc_netaddr_issitelocal(&netaddr));
439	}
440	return (false);
441}
442
443bool
444isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
445	isc_netaddr_t netaddr;
446
447	if (sockaddr->type.sa.sa_family == AF_INET6) {
448		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
449		return (isc_netaddr_islinklocal(&netaddr));
450	}
451	return (false);
452}
453
454bool
455isc_sockaddr_isnetzero(const isc_sockaddr_t *sockaddr) {
456	isc_netaddr_t netaddr;
457
458	if (sockaddr->type.sa.sa_family == AF_INET) {
459		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
460		return (isc_netaddr_isnetzero(&netaddr));
461	}
462	return (false);
463}
464
465isc_result_t
466isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
467	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path)) {
468		return (ISC_R_NOSPACE);
469	}
470	memset(sockaddr, 0, sizeof(*sockaddr));
471	sockaddr->length = sizeof(sockaddr->type.sunix);
472	sockaddr->type.sunix.sun_family = AF_UNIX;
473	strlcpy(sockaddr->type.sunix.sun_path, path,
474		sizeof(sockaddr->type.sunix.sun_path));
475	return (ISC_R_SUCCESS);
476}
477
478isc_result_t
479isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa) {
480	unsigned int length = 0;
481
482	switch (sa->sa_family) {
483	case AF_INET:
484		length = sizeof(isa->type.sin);
485		break;
486	case AF_INET6:
487		length = sizeof(isa->type.sin6);
488		break;
489	case AF_UNIX:
490		length = sizeof(isa->type.sunix);
491		break;
492	default:
493		return (ISC_R_NOTIMPLEMENTED);
494	}
495
496	memset(isa, 0, sizeof(isc_sockaddr_t));
497	memmove(isa, sa, length);
498	isa->length = length;
499
500	return (ISC_R_SUCCESS);
501}
502