sockaddr.c revision 1.13 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