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