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