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