1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12
13 /*! \file */
14
15 #include <config.h>
16
17 #include <stdbool.h>
18 #include <stdio.h>
19
20 #include <isc/buffer.h>
21 #include <isc/hash.h>
22 #include <isc/msgs.h>
23 #include <isc/netaddr.h>
24 #include <isc/print.h>
25 #include <isc/region.h>
26 #include <isc/sockaddr.h>
27 #include <isc/string.h>
28 #include <isc/util.h>
29
30 bool
isc_sockaddr_equal(const isc_sockaddr_t * a,const isc_sockaddr_t * b)31 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
32 return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
33 ISC_SOCKADDR_CMPPORT|
34 ISC_SOCKADDR_CMPSCOPE));
35 }
36
37 bool
isc_sockaddr_eqaddr(const isc_sockaddr_t * a,const isc_sockaddr_t * b)38 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
39 return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
40 ISC_SOCKADDR_CMPSCOPE));
41 }
42
43 bool
isc_sockaddr_compare(const isc_sockaddr_t * a,const isc_sockaddr_t * b,unsigned int flags)44 isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
45 unsigned int flags)
46 {
47 REQUIRE(a != NULL && b != NULL);
48
49 if (a->length != b->length)
50 return (false);
51
52 /*
53 * We don't just memcmp because the sin_zero field isn't always
54 * zero.
55 */
56
57 if (a->type.sa.sa_family != b->type.sa.sa_family)
58 return (false);
59 switch (a->type.sa.sa_family) {
60 case AF_INET:
61 if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
62 memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
63 sizeof(a->type.sin.sin_addr)) != 0)
64 return (false);
65 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
66 a->type.sin.sin_port != b->type.sin.sin_port)
67 return (false);
68 break;
69 case AF_INET6:
70 if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
71 memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
72 sizeof(a->type.sin6.sin6_addr)) != 0)
73 return (false);
74 #ifdef ISC_PLATFORM_HAVESCOPEID
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 #endif
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
isc_sockaddr_eqaddrprefix(const isc_sockaddr_t * a,const isc_sockaddr_t * b,unsigned int prefixlen)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
isc_sockaddr_totext(const isc_sockaddr_t * sockaddr,isc_buffer_t * target)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_PLATFORM_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(
136 target,
137 (const unsigned char *)sockaddr->type.sunix.sun_path,
138 plen);
139
140 /*
141 * Null terminate after used region.
142 */
143 isc_buffer_availableregion(target, &avail);
144 INSIST(avail.length >= 1);
145 avail.base[0] = '\0';
146
147 return (ISC_R_SUCCESS);
148 #endif
149 default:
150 return (ISC_R_FAILURE);
151 }
152
153 plen = strlen(pbuf);
154 INSIST(plen < sizeof(pbuf));
155
156 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
157 result = isc_netaddr_totext(&netaddr, target);
158 if (result != ISC_R_SUCCESS)
159 return (result);
160
161 if (1 + plen + 1 > isc_buffer_availablelength(target))
162 return (ISC_R_NOSPACE);
163
164 isc_buffer_putmem(target, (const unsigned char *)"#", 1);
165 isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
166
167 /*
168 * Null terminate after used region.
169 */
170 isc_buffer_availableregion(target, &avail);
171 INSIST(avail.length >= 1);
172 avail.base[0] = '\0';
173
174 return (ISC_R_SUCCESS);
175 }
176
177 void
isc_sockaddr_format(const isc_sockaddr_t * sa,char * array,unsigned int size)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 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
193 ISC_MSG_UNKNOWNADDR,
194 "<unknown address, family %u>"),
195 sa->type.sa.sa_family);
196 array[size - 1] = '\0';
197 }
198 }
199
200 unsigned int
isc_sockaddr_hash(const isc_sockaddr_t * sockaddr,bool address_only)201 isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only) {
202 unsigned int length = 0;
203 const unsigned char *s = NULL;
204 unsigned int h = 0;
205 unsigned int p = 0;
206 const struct in6_addr *in6;
207
208 REQUIRE(sockaddr != NULL);
209
210 switch (sockaddr->type.sa.sa_family) {
211 case AF_INET:
212 s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
213 p = ntohs(sockaddr->type.sin.sin_port);
214 length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
215 break;
216 case AF_INET6:
217 in6 = &sockaddr->type.sin6.sin6_addr;
218 s = (const unsigned char *)in6;
219 if (IN6_IS_ADDR_V4MAPPED(in6)) {
220 s += 12;
221 length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
222 } else
223 length = sizeof(sockaddr->type.sin6.sin6_addr);
224 p = ntohs(sockaddr->type.sin6.sin6_port);
225 break;
226 default:
227 UNEXPECTED_ERROR(__FILE__, __LINE__,
228 isc_msgcat_get(isc_msgcat,
229 ISC_MSGSET_SOCKADDR,
230 ISC_MSG_UNKNOWNFAMILY,
231 "unknown address family: %d"),
232 (int)sockaddr->type.sa.sa_family);
233 s = (const unsigned char *)&sockaddr->type;
234 length = sockaddr->length;
235 p = 0;
236 }
237
238 h = isc_hash_function(s, length, true, NULL);
239 if (!address_only)
240 h = isc_hash_function(&p, sizeof(p), true, &h);
241
242 return (h);
243 }
244
245 void
isc_sockaddr_any(isc_sockaddr_t * sockaddr)246 isc_sockaddr_any(isc_sockaddr_t *sockaddr)
247 {
248 memset(sockaddr, 0, sizeof(*sockaddr));
249 sockaddr->type.sin.sin_family = AF_INET;
250 #ifdef ISC_PLATFORM_HAVESALEN
251 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
252 #endif
253 sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
254 sockaddr->type.sin.sin_port = 0;
255 sockaddr->length = sizeof(sockaddr->type.sin);
256 ISC_LINK_INIT(sockaddr, link);
257 }
258
259 void
isc_sockaddr_any6(isc_sockaddr_t * sockaddr)260 isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
261 {
262 memset(sockaddr, 0, sizeof(*sockaddr));
263 sockaddr->type.sin6.sin6_family = AF_INET6;
264 #ifdef ISC_PLATFORM_HAVESALEN
265 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
266 #endif
267 sockaddr->type.sin6.sin6_addr = in6addr_any;
268 sockaddr->type.sin6.sin6_port = 0;
269 sockaddr->length = sizeof(sockaddr->type.sin6);
270 ISC_LINK_INIT(sockaddr, link);
271 }
272
273 void
isc_sockaddr_fromin(isc_sockaddr_t * sockaddr,const struct in_addr * ina,in_port_t port)274 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
275 in_port_t port)
276 {
277 memset(sockaddr, 0, sizeof(*sockaddr));
278 sockaddr->type.sin.sin_family = AF_INET;
279 #ifdef ISC_PLATFORM_HAVESALEN
280 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
281 #endif
282 sockaddr->type.sin.sin_addr = *ina;
283 sockaddr->type.sin.sin_port = htons(port);
284 sockaddr->length = sizeof(sockaddr->type.sin);
285 ISC_LINK_INIT(sockaddr, link);
286 }
287
288 void
isc_sockaddr_anyofpf(isc_sockaddr_t * sockaddr,int pf)289 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
290 switch (pf) {
291 case AF_INET:
292 isc_sockaddr_any(sockaddr);
293 break;
294 case AF_INET6:
295 isc_sockaddr_any6(sockaddr);
296 break;
297 default:
298 INSIST(0);
299 ISC_UNREACHABLE();
300 }
301 }
302
303 void
isc_sockaddr_fromin6(isc_sockaddr_t * sockaddr,const struct in6_addr * ina6,in_port_t port)304 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
305 in_port_t port)
306 {
307 memset(sockaddr, 0, sizeof(*sockaddr));
308 sockaddr->type.sin6.sin6_family = AF_INET6;
309 #ifdef ISC_PLATFORM_HAVESALEN
310 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
311 #endif
312 sockaddr->type.sin6.sin6_addr = *ina6;
313 sockaddr->type.sin6.sin6_port = htons(port);
314 sockaddr->length = sizeof(sockaddr->type.sin6);
315 ISC_LINK_INIT(sockaddr, link);
316 }
317
318 void
isc_sockaddr_v6fromin(isc_sockaddr_t * sockaddr,const struct in_addr * ina,in_port_t port)319 isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
320 in_port_t port)
321 {
322 memset(sockaddr, 0, sizeof(*sockaddr));
323 sockaddr->type.sin6.sin6_family = AF_INET6;
324 #ifdef ISC_PLATFORM_HAVESALEN
325 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
326 #endif
327 sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
328 sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
329 memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
330 sockaddr->type.sin6.sin6_port = htons(port);
331 sockaddr->length = sizeof(sockaddr->type.sin6);
332 ISC_LINK_INIT(sockaddr, link);
333 }
334
335 int
isc_sockaddr_pf(const isc_sockaddr_t * sockaddr)336 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
337
338 /*
339 * Get the protocol family of 'sockaddr'.
340 */
341
342 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
343 /*
344 * Assume that PF_xxx == AF_xxx for all AF and PF.
345 */
346 return (sockaddr->type.sa.sa_family);
347 #else
348 switch (sockaddr->type.sa.sa_family) {
349 case AF_INET:
350 return (PF_INET);
351 case AF_INET6:
352 return (PF_INET6);
353 default:
354 FATAL_ERROR(__FILE__, __LINE__,
355 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
356 ISC_MSG_UNKNOWNFAMILY,
357 "unknown address family: %d"),
358 (int)sockaddr->type.sa.sa_family);
359 }
360 #endif
361 }
362
363 void
isc_sockaddr_fromnetaddr(isc_sockaddr_t * sockaddr,const isc_netaddr_t * na,in_port_t port)364 isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
365 in_port_t port)
366 {
367 memset(sockaddr, 0, sizeof(*sockaddr));
368 sockaddr->type.sin.sin_family = na->family;
369 switch (na->family) {
370 case AF_INET:
371 sockaddr->length = sizeof(sockaddr->type.sin);
372 #ifdef ISC_PLATFORM_HAVESALEN
373 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
374 #endif
375 sockaddr->type.sin.sin_addr = na->type.in;
376 sockaddr->type.sin.sin_port = htons(port);
377 break;
378 case AF_INET6:
379 sockaddr->length = sizeof(sockaddr->type.sin6);
380 #ifdef ISC_PLATFORM_HAVESALEN
381 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
382 #endif
383 memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
384 #ifdef ISC_PLATFORM_HAVESCOPEID
385 sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
386 #endif
387 sockaddr->type.sin6.sin6_port = htons(port);
388 break;
389 default:
390 INSIST(0);
391 ISC_UNREACHABLE();
392 }
393 ISC_LINK_INIT(sockaddr, link);
394 }
395
396 void
isc_sockaddr_setport(isc_sockaddr_t * sockaddr,in_port_t port)397 isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
398 switch (sockaddr->type.sa.sa_family) {
399 case AF_INET:
400 sockaddr->type.sin.sin_port = htons(port);
401 break;
402 case AF_INET6:
403 sockaddr->type.sin6.sin6_port = htons(port);
404 break;
405 default:
406 FATAL_ERROR(__FILE__, __LINE__,
407 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
408 ISC_MSG_UNKNOWNFAMILY,
409 "unknown address family: %d"),
410 (int)sockaddr->type.sa.sa_family);
411 }
412 }
413
414 in_port_t
isc_sockaddr_getport(const isc_sockaddr_t * sockaddr)415 isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
416 in_port_t port = 0;
417
418 switch (sockaddr->type.sa.sa_family) {
419 case AF_INET:
420 port = ntohs(sockaddr->type.sin.sin_port);
421 break;
422 case AF_INET6:
423 port = ntohs(sockaddr->type.sin6.sin6_port);
424 break;
425 default:
426 FATAL_ERROR(__FILE__, __LINE__,
427 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
428 ISC_MSG_UNKNOWNFAMILY,
429 "unknown address family: %d"),
430 (int)sockaddr->type.sa.sa_family);
431 }
432
433 return (port);
434 }
435
436 bool
isc_sockaddr_ismulticast(const isc_sockaddr_t * sockaddr)437 isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
438 isc_netaddr_t netaddr;
439
440 if (sockaddr->type.sa.sa_family == AF_INET ||
441 sockaddr->type.sa.sa_family == AF_INET6) {
442 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
443 return (isc_netaddr_ismulticast(&netaddr));
444 }
445 return (false);
446 }
447
448 bool
isc_sockaddr_isexperimental(const isc_sockaddr_t * sockaddr)449 isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
450 isc_netaddr_t netaddr;
451
452 if (sockaddr->type.sa.sa_family == AF_INET) {
453 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
454 return (isc_netaddr_isexperimental(&netaddr));
455 }
456 return (false);
457 }
458
459 bool
isc_sockaddr_issitelocal(const isc_sockaddr_t * sockaddr)460 isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
461 isc_netaddr_t netaddr;
462
463 if (sockaddr->type.sa.sa_family == AF_INET6) {
464 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
465 return (isc_netaddr_issitelocal(&netaddr));
466 }
467 return (false);
468 }
469
470 bool
isc_sockaddr_islinklocal(const isc_sockaddr_t * sockaddr)471 isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
472 isc_netaddr_t netaddr;
473
474 if (sockaddr->type.sa.sa_family == AF_INET6) {
475 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
476 return (isc_netaddr_islinklocal(&netaddr));
477 }
478 return (false);
479 }
480
481 bool
isc_sockaddr_isnetzero(const isc_sockaddr_t * sockaddr)482 isc_sockaddr_isnetzero(const isc_sockaddr_t *sockaddr) {
483 isc_netaddr_t netaddr;
484
485 if (sockaddr->type.sa.sa_family == AF_INET) {
486 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
487 return (isc_netaddr_isnetzero(&netaddr));
488 }
489 return (false);
490 }
491
492 isc_result_t
isc_sockaddr_frompath(isc_sockaddr_t * sockaddr,const char * path)493 isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
494 #ifdef ISC_PLATFORM_HAVESYSUNH
495 if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
496 return (ISC_R_NOSPACE);
497 memset(sockaddr, 0, sizeof(*sockaddr));
498 sockaddr->length = sizeof(sockaddr->type.sunix);
499 sockaddr->type.sunix.sun_family = AF_UNIX;
500 #ifdef ISC_PLATFORM_HAVESALEN
501 sockaddr->type.sunix.sun_len =
502 (unsigned char)sizeof(sockaddr->type.sunix);
503 #endif
504 strlcpy(sockaddr->type.sunix.sun_path, path,
505 sizeof(sockaddr->type.sunix.sun_path));
506 return (ISC_R_SUCCESS);
507 #else
508 UNUSED(sockaddr);
509 UNUSED(path);
510 return (ISC_R_NOTIMPLEMENTED);
511 #endif
512 }
513