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