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