sockaddr.c revision 1.3 1 /* $NetBSD: sockaddr.c,v 1.3 2019/01/09 16:55:14 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/msgs.h>
25 #include <isc/netaddr.h>
26 #include <isc/print.h>
27 #include <isc/region.h>
28 #include <isc/sockaddr.h>
29 #include <isc/string.h>
30 #include <isc/util.h>
31
32 bool
33 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
34 return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
35 ISC_SOCKADDR_CMPPORT|
36 ISC_SOCKADDR_CMPSCOPE));
37 }
38
39 bool
40 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
41 return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
42 ISC_SOCKADDR_CMPSCOPE));
43 }
44
45 bool
46 isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
47 unsigned int flags)
48 {
49 REQUIRE(a != NULL && b != NULL);
50
51 if (a->length != b->length)
52 return (false);
53
54 /*
55 * We don't just memcmp because the sin_zero field isn't always
56 * zero.
57 */
58
59 if (a->type.sa.sa_family != b->type.sa.sa_family)
60 return (false);
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 return (false);
67 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
68 a->type.sin.sin_port != b->type.sin.sin_port)
69 return (false);
70 break;
71 case AF_INET6:
72 if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
73 memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
74 sizeof(a->type.sin6.sin6_addr)) != 0)
75 return (false);
76 /*
77 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
78 * false if one of the scopes in zero.
79 */
80 if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
81 a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
82 ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
83 (a->type.sin6.sin6_scope_id != 0 &&
84 b->type.sin6.sin6_scope_id != 0)))
85 return (false);
86 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
87 a->type.sin6.sin6_port != b->type.sin6.sin6_port)
88 return (false);
89 break;
90 default:
91 if (memcmp(&a->type, &b->type, a->length) != 0)
92 return (false);
93 }
94 return (true);
95 }
96
97 bool
98 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
99 unsigned int prefixlen)
100 {
101 isc_netaddr_t na, nb;
102 isc_netaddr_fromsockaddr(&na, a);
103 isc_netaddr_fromsockaddr(&nb, b);
104 return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
105 }
106
107 isc_result_t
108 isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
109 isc_result_t result;
110 isc_netaddr_t netaddr;
111 char pbuf[sizeof("65000")];
112 unsigned int plen;
113 isc_region_t avail;
114
115 REQUIRE(sockaddr != NULL);
116
117 /*
118 * Do the port first, giving us the opportunity to check for
119 * unsupported address families before calling
120 * isc_netaddr_fromsockaddr().
121 */
122 switch (sockaddr->type.sa.sa_family) {
123 case AF_INET:
124 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
125 break;
126 case AF_INET6:
127 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
128 break;
129 #ifdef ISC_PLAFORM_HAVESYSUNH
130 case AF_UNIX:
131 plen = strlen(sockaddr->type.sunix.sun_path);
132 if (plen >= isc_buffer_availablelength(target))
133 return (ISC_R_NOSPACE);
134
135 isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
136
137 /*
138 * Null terminate after used region.
139 */
140 isc_buffer_availableregion(target, &avail);
141 INSIST(avail.length >= 1);
142 avail.base[0] = '\0';
143
144 return (ISC_R_SUCCESS);
145 #endif
146 default:
147 return (ISC_R_FAILURE);
148 }
149
150 plen = strlen(pbuf);
151 INSIST(plen < sizeof(pbuf));
152
153 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
154 result = isc_netaddr_totext(&netaddr, target);
155 if (result != ISC_R_SUCCESS)
156 return (result);
157
158 if (1 + plen + 1 > isc_buffer_availablelength(target))
159 return (ISC_R_NOSPACE);
160
161 isc_buffer_putmem(target, (const unsigned char *)"#", 1);
162 isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
163
164 /*
165 * Null terminate after used region.
166 */
167 isc_buffer_availableregion(target, &avail);
168 INSIST(avail.length >= 1);
169 avail.base[0] = '\0';
170
171 return (ISC_R_SUCCESS);
172 }
173
174 void
175 isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
176 isc_result_t result;
177 isc_buffer_t buf;
178
179 if (size == 0U)
180 return;
181
182 isc_buffer_init(&buf, array, size);
183 result = isc_sockaddr_totext(sa, &buf);
184 if (result != ISC_R_SUCCESS) {
185 /*
186 * The message is the same as in netaddr.c.
187 */
188 snprintf(array, size,
189 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
190 ISC_MSG_UNKNOWNADDR,
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 isc_msgcat_get(isc_msgcat,
226 ISC_MSGSET_SOCKADDR,
227 ISC_MSG_UNKNOWNFAMILY,
228 "unknown address family: %d"),
229 (int)sockaddr->type.sa.sa_family);
230 s = (const unsigned char *)&sockaddr->type;
231 length = sockaddr->length;
232 p = 0;
233 }
234
235 h = isc_hash_function(s, length, true, NULL);
236 if (!address_only)
237 h = isc_hash_function(&p, sizeof(p), true, &h);
238
239 return (h);
240 }
241
242 void
243 isc_sockaddr_any(isc_sockaddr_t *sockaddr)
244 {
245 memset(sockaddr, 0, sizeof(*sockaddr));
246 sockaddr->type.sin.sin_family = AF_INET;
247 sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
248 sockaddr->type.sin.sin_port = 0;
249 sockaddr->length = sizeof(sockaddr->type.sin);
250 ISC_LINK_INIT(sockaddr, link);
251 }
252
253 void
254 isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
255 {
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 {
268 memset(sockaddr, 0, sizeof(*sockaddr));
269 sockaddr->type.sin.sin_family = AF_INET;
270 sockaddr->type.sin.sin_addr = *ina;
271 sockaddr->type.sin.sin_port = htons(port);
272 sockaddr->length = sizeof(sockaddr->type.sin);
273 ISC_LINK_INIT(sockaddr, link);
274 }
275
276 void
277 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
278 switch (pf) {
279 case AF_INET:
280 isc_sockaddr_any(sockaddr);
281 break;
282 case AF_INET6:
283 isc_sockaddr_any6(sockaddr);
284 break;
285 default:
286 INSIST(0);
287 ISC_UNREACHABLE();
288 }
289 }
290
291 void
292 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
293 in_port_t port)
294 {
295 memset(sockaddr, 0, sizeof(*sockaddr));
296 sockaddr->type.sin6.sin6_family = AF_INET6;
297 sockaddr->type.sin6.sin6_addr = *ina6;
298 sockaddr->type.sin6.sin6_port = htons(port);
299 sockaddr->length = sizeof(sockaddr->type.sin6);
300 ISC_LINK_INIT(sockaddr, link);
301 }
302
303 void
304 isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
305 in_port_t port)
306 {
307 memset(sockaddr, 0, sizeof(*sockaddr));
308 sockaddr->type.sin6.sin6_family = AF_INET6;
309 sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
310 sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
311 memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
312 sockaddr->type.sin6.sin6_port = htons(port);
313 sockaddr->length = sizeof(sockaddr->type.sin6);
314 ISC_LINK_INIT(sockaddr, link);
315 }
316
317 int
318 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
319
320 /*
321 * Get the protocol family of 'sockaddr'.
322 */
323
324 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
325 /*
326 * Assume that PF_xxx == AF_xxx for all AF and PF.
327 */
328 return (sockaddr->type.sa.sa_family);
329 #else
330 switch (sockaddr->type.sa.sa_family) {
331 case AF_INET:
332 return (PF_INET);
333 case AF_INET6:
334 return (PF_INET6);
335 default:
336 FATAL_ERROR(__FILE__, __LINE__,
337 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
338 ISC_MSG_UNKNOWNFAMILY,
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 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
382 ISC_MSG_UNKNOWNFAMILY,
383 "unknown address family: %d"),
384 (int)sockaddr->type.sa.sa_family);
385 }
386 }
387
388 in_port_t
389 isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
390 in_port_t port = 0;
391
392 switch (sockaddr->type.sa.sa_family) {
393 case AF_INET:
394 port = ntohs(sockaddr->type.sin.sin_port);
395 break;
396 case AF_INET6:
397 port = ntohs(sockaddr->type.sin6.sin6_port);
398 break;
399 default:
400 FATAL_ERROR(__FILE__, __LINE__,
401 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
402 ISC_MSG_UNKNOWNFAMILY,
403 "unknown address family: %d"),
404 (int)sockaddr->type.sa.sa_family);
405 }
406
407 return (port);
408 }
409
410 bool
411 isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
412 isc_netaddr_t netaddr;
413
414 if (sockaddr->type.sa.sa_family == AF_INET ||
415 sockaddr->type.sa.sa_family == AF_INET6) {
416 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
417 return (isc_netaddr_ismulticast(&netaddr));
418 }
419 return (false);
420 }
421
422 bool
423 isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
424 isc_netaddr_t netaddr;
425
426 if (sockaddr->type.sa.sa_family == AF_INET) {
427 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
428 return (isc_netaddr_isexperimental(&netaddr));
429 }
430 return (false);
431 }
432
433 bool
434 isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
435 isc_netaddr_t netaddr;
436
437 if (sockaddr->type.sa.sa_family == AF_INET6) {
438 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
439 return (isc_netaddr_issitelocal(&netaddr));
440 }
441 return (false);
442 }
443
444 bool
445 isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
446 isc_netaddr_t netaddr;
447
448 if (sockaddr->type.sa.sa_family == AF_INET6) {
449 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
450 return (isc_netaddr_islinklocal(&netaddr));
451 }
452 return (false);
453 }
454
455 bool
456 isc_sockaddr_isnetzero(const isc_sockaddr_t *sockaddr) {
457 isc_netaddr_t netaddr;
458
459 if (sockaddr->type.sa.sa_family == AF_INET) {
460 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
461 return (isc_netaddr_isnetzero(&netaddr));
462 }
463 return (false);
464 }
465
466 isc_result_t
467 isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
468 #ifdef ISC_PLATFORM_HAVESYSUNH
469 if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
470 return (ISC_R_NOSPACE);
471 memset(sockaddr, 0, sizeof(*sockaddr));
472 sockaddr->length = sizeof(sockaddr->type.sunix);
473 sockaddr->type.sunix.sun_family = AF_UNIX;
474 strlcpy(sockaddr->type.sunix.sun_path, path,
475 sizeof(sockaddr->type.sunix.sun_path));
476 return (ISC_R_SUCCESS);
477 #else
478 UNUSED(sockaddr);
479 UNUSED(path);
480 return (ISC_R_NOTIMPLEMENTED);
481 #endif
482 }
483