xref: /minix/external/bsd/bind/dist/lib/isc/sockaddr.c (revision 00b67f09)
1 /*	$NetBSD: sockaddr.c,v 1.7 2014/12/10 04:37:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2007, 2010-2012, 2014  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id */
21 
22 /*! \file */
23 
24 #include <config.h>
25 
26 #include <stdio.h>
27 
28 #include <isc/buffer.h>
29 #include <isc/hash.h>
30 #include <isc/msgs.h>
31 #include <isc/netaddr.h>
32 #include <isc/print.h>
33 #include <isc/region.h>
34 #include <isc/sockaddr.h>
35 #include <isc/string.h>
36 #include <isc/util.h>
37 
38 isc_boolean_t
isc_sockaddr_equal(const isc_sockaddr_t * a,const isc_sockaddr_t * b)39 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
40 	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
41 					   ISC_SOCKADDR_CMPPORT|
42 					   ISC_SOCKADDR_CMPSCOPE));
43 }
44 
45 isc_boolean_t
isc_sockaddr_eqaddr(const isc_sockaddr_t * a,const isc_sockaddr_t * b)46 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
47 	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
48 					   ISC_SOCKADDR_CMPSCOPE));
49 }
50 
51 isc_boolean_t
isc_sockaddr_compare(const isc_sockaddr_t * a,const isc_sockaddr_t * b,unsigned int flags)52 isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
53 		     unsigned int flags)
54 {
55 	REQUIRE(a != NULL && b != NULL);
56 
57 	if (a->length != b->length)
58 		return (ISC_FALSE);
59 
60 	/*
61 	 * We don't just memcmp because the sin_zero field isn't always
62 	 * zero.
63 	 */
64 
65 	if (a->type.sa.sa_family != b->type.sa.sa_family)
66 		return (ISC_FALSE);
67 	switch (a->type.sa.sa_family) {
68 	case AF_INET:
69 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
70 		    memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
71 			   sizeof(a->type.sin.sin_addr)) != 0)
72 			return (ISC_FALSE);
73 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
74 		    a->type.sin.sin_port != b->type.sin.sin_port)
75 			return (ISC_FALSE);
76 		break;
77 	case AF_INET6:
78 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
79 		    memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
80 			   sizeof(a->type.sin6.sin6_addr)) != 0)
81 			return (ISC_FALSE);
82 #ifdef ISC_PLATFORM_HAVESCOPEID
83 		/*
84 		 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
85 		 * ISC_FALSE if one of the scopes in zero.
86 		 */
87 		if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
88 		    a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
89 		    ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
90 		      (a->type.sin6.sin6_scope_id != 0 &&
91 		       b->type.sin6.sin6_scope_id != 0)))
92 			return (ISC_FALSE);
93 #endif
94 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
95 		    a->type.sin6.sin6_port != b->type.sin6.sin6_port)
96 			return (ISC_FALSE);
97 		break;
98 	default:
99 		if (memcmp(&a->type, &b->type, a->length) != 0)
100 			return (ISC_FALSE);
101 	}
102 	return (ISC_TRUE);
103 }
104 
105 isc_boolean_t
isc_sockaddr_eqaddrprefix(const isc_sockaddr_t * a,const isc_sockaddr_t * b,unsigned int prefixlen)106 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
107 			  unsigned int prefixlen)
108 {
109 	isc_netaddr_t na, nb;
110 	isc_netaddr_fromsockaddr(&na, a);
111 	isc_netaddr_fromsockaddr(&nb, b);
112 	return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
113 }
114 
115 isc_result_t
isc_sockaddr_totext(const isc_sockaddr_t * sockaddr,isc_buffer_t * target)116 isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
117 	isc_result_t result;
118 	isc_netaddr_t netaddr;
119 	char pbuf[sizeof("65000")];
120 	unsigned int plen;
121 	isc_region_t avail;
122 
123 	REQUIRE(sockaddr != NULL);
124 
125 	/*
126 	 * Do the port first, giving us the opportunity to check for
127 	 * unsupported address families before calling
128 	 * isc_netaddr_fromsockaddr().
129 	 */
130 	switch (sockaddr->type.sa.sa_family) {
131 	case AF_INET:
132 		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
133 		break;
134 	case AF_INET6:
135 		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
136 		break;
137 #ifdef ISC_PLAFORM_HAVESYSUNH
138 	case AF_UNIX:
139 		plen = strlen(sockaddr->type.sunix.sun_path);
140 		if (plen >= isc_buffer_availablelength(target))
141 			return (ISC_R_NOSPACE);
142 
143 		isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
144 
145 		/*
146 		 * Null terminate after used region.
147 		 */
148 		isc_buffer_availableregion(target, &avail);
149 		INSIST(avail.length >= 1);
150 		avail.base[0] = '\0';
151 
152 		return (ISC_R_SUCCESS);
153 #endif
154 	default:
155 		return (ISC_R_FAILURE);
156 	}
157 
158 	plen = strlen(pbuf);
159 	INSIST(plen < sizeof(pbuf));
160 
161 	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
162 	result = isc_netaddr_totext(&netaddr, target);
163 	if (result != ISC_R_SUCCESS)
164 		return (result);
165 
166 	if (1 + plen + 1 > isc_buffer_availablelength(target))
167 		return (ISC_R_NOSPACE);
168 
169 	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
170 	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
171 
172 	/*
173 	 * Null terminate after used region.
174 	 */
175 	isc_buffer_availableregion(target, &avail);
176 	INSIST(avail.length >= 1);
177 	avail.base[0] = '\0';
178 
179 	return (ISC_R_SUCCESS);
180 }
181 
182 void
isc_sockaddr_format(const isc_sockaddr_t * sa,char * array,unsigned int size)183 isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
184 	isc_result_t result;
185 	isc_buffer_t buf;
186 
187 	if (size == 0U)
188 		return;
189 
190 	isc_buffer_init(&buf, array, size);
191 	result = isc_sockaddr_totext(sa, &buf);
192 	if (result != ISC_R_SUCCESS) {
193 		/*
194 		 * The message is the same as in netaddr.c.
195 		 */
196 		snprintf(array, size,
197 			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
198 					ISC_MSG_UNKNOWNADDR,
199 					"<unknown address, family %u>"),
200 			 sa->type.sa.sa_family);
201 		array[size - 1] = '\0';
202 	}
203 }
204 
205 unsigned int
isc_sockaddr_hash(const isc_sockaddr_t * sockaddr,isc_boolean_t address_only)206 isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
207 	unsigned int length = 0;
208 	const unsigned char *s = NULL;
209 	unsigned int h = 0;
210 	unsigned int g;
211 	unsigned int p = 0;
212 	const struct in6_addr *in6;
213 
214 	REQUIRE(sockaddr != NULL);
215 
216 	switch (sockaddr->type.sa.sa_family) {
217 	case AF_INET:
218 		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
219 		p = ntohs(sockaddr->type.sin.sin_port);
220 		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
221 		break;
222 	case AF_INET6:
223 		in6 = &sockaddr->type.sin6.sin6_addr;
224 		s = (const unsigned char *)in6;
225 		if (IN6_IS_ADDR_V4MAPPED(in6)) {
226 			s += 12;
227 			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
228 		} else
229 			length = sizeof(sockaddr->type.sin6.sin6_addr);
230 		p = ntohs(sockaddr->type.sin6.sin6_port);
231 		break;
232 	default:
233 		UNEXPECTED_ERROR(__FILE__, __LINE__,
234 				 isc_msgcat_get(isc_msgcat,
235 						ISC_MSGSET_SOCKADDR,
236 						ISC_MSG_UNKNOWNFAMILY,
237 						"unknown address family: %d"),
238 					     (int)sockaddr->type.sa.sa_family);
239 		s = (const unsigned char *)&sockaddr->type;
240 		length = sockaddr->length;
241 		p = 0;
242 	}
243 
244 	h = isc_hash_calc(s, length, ISC_TRUE);
245 	if (!address_only) {
246 		g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
247 				  ISC_TRUE);
248 		h = h ^ g; /* XXX: we should concatenate h and p first */
249 	}
250 
251 	return (h);
252 }
253 
254 void
isc_sockaddr_any(isc_sockaddr_t * sockaddr)255 isc_sockaddr_any(isc_sockaddr_t *sockaddr)
256 {
257 	memset(sockaddr, 0, sizeof(*sockaddr));
258 	sockaddr->type.sin.sin_family = AF_INET;
259 #ifdef ISC_PLATFORM_HAVESALEN
260 	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
261 #endif
262 	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
263 	sockaddr->type.sin.sin_port = 0;
264 	sockaddr->length = sizeof(sockaddr->type.sin);
265 	ISC_LINK_INIT(sockaddr, link);
266 }
267 
268 void
isc_sockaddr_any6(isc_sockaddr_t * sockaddr)269 isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
270 {
271 	memset(sockaddr, 0, sizeof(*sockaddr));
272 	sockaddr->type.sin6.sin6_family = AF_INET6;
273 #ifdef ISC_PLATFORM_HAVESALEN
274 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
275 #endif
276 	sockaddr->type.sin6.sin6_addr = in6addr_any;
277 	sockaddr->type.sin6.sin6_port = 0;
278 	sockaddr->length = sizeof(sockaddr->type.sin6);
279 	ISC_LINK_INIT(sockaddr, link);
280 }
281 
282 void
isc_sockaddr_fromin(isc_sockaddr_t * sockaddr,const struct in_addr * ina,in_port_t port)283 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
284 		    in_port_t port)
285 {
286 	memset(sockaddr, 0, sizeof(*sockaddr));
287 	sockaddr->type.sin.sin_family = AF_INET;
288 #ifdef ISC_PLATFORM_HAVESALEN
289 	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
290 #endif
291 	sockaddr->type.sin.sin_addr = *ina;
292 	sockaddr->type.sin.sin_port = htons(port);
293 	sockaddr->length = sizeof(sockaddr->type.sin);
294 	ISC_LINK_INIT(sockaddr, link);
295 }
296 
297 void
isc_sockaddr_anyofpf(isc_sockaddr_t * sockaddr,int pf)298 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
299      switch (pf) {
300      case AF_INET:
301 	     isc_sockaddr_any(sockaddr);
302 	     break;
303      case AF_INET6:
304 	     isc_sockaddr_any6(sockaddr);
305 	     break;
306      default:
307 	     INSIST(0);
308      }
309 }
310 
311 void
isc_sockaddr_fromin6(isc_sockaddr_t * sockaddr,const struct in6_addr * ina6,in_port_t port)312 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
313 		     in_port_t port)
314 {
315 	memset(sockaddr, 0, sizeof(*sockaddr));
316 	sockaddr->type.sin6.sin6_family = AF_INET6;
317 #ifdef ISC_PLATFORM_HAVESALEN
318 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
319 #endif
320 	sockaddr->type.sin6.sin6_addr = *ina6;
321 	sockaddr->type.sin6.sin6_port = htons(port);
322 	sockaddr->length = sizeof(sockaddr->type.sin6);
323 	ISC_LINK_INIT(sockaddr, link);
324 }
325 
326 void
isc_sockaddr_v6fromin(isc_sockaddr_t * sockaddr,const struct in_addr * ina,in_port_t port)327 isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
328 		      in_port_t port)
329 {
330 	memset(sockaddr, 0, sizeof(*sockaddr));
331 	sockaddr->type.sin6.sin6_family = AF_INET6;
332 #ifdef ISC_PLATFORM_HAVESALEN
333 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
334 #endif
335 	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
336 	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
337 	memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
338 	sockaddr->type.sin6.sin6_port = htons(port);
339 	sockaddr->length = sizeof(sockaddr->type.sin6);
340 	ISC_LINK_INIT(sockaddr, link);
341 }
342 
343 int
isc_sockaddr_pf(const isc_sockaddr_t * sockaddr)344 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
345 
346 	/*
347 	 * Get the protocol family of 'sockaddr'.
348 	 */
349 
350 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
351 	/*
352 	 * Assume that PF_xxx == AF_xxx for all AF and PF.
353 	 */
354 	return (sockaddr->type.sa.sa_family);
355 #else
356 	switch (sockaddr->type.sa.sa_family) {
357 	case AF_INET:
358 		return (PF_INET);
359 	case AF_INET6:
360 		return (PF_INET6);
361 	default:
362 		FATAL_ERROR(__FILE__, __LINE__,
363 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
364 					   ISC_MSG_UNKNOWNFAMILY,
365 					   "unknown address family: %d"),
366 			    (int)sockaddr->type.sa.sa_family);
367 	}
368 #endif
369 }
370 
371 void
isc_sockaddr_fromnetaddr(isc_sockaddr_t * sockaddr,const isc_netaddr_t * na,in_port_t port)372 isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
373 		    in_port_t port)
374 {
375 	memset(sockaddr, 0, sizeof(*sockaddr));
376 	sockaddr->type.sin.sin_family = na->family;
377 	switch (na->family) {
378 	case AF_INET:
379 		sockaddr->length = sizeof(sockaddr->type.sin);
380 #ifdef ISC_PLATFORM_HAVESALEN
381 		sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
382 #endif
383 		sockaddr->type.sin.sin_addr = na->type.in;
384 		sockaddr->type.sin.sin_port = htons(port);
385 		break;
386 	case AF_INET6:
387 		sockaddr->length = sizeof(sockaddr->type.sin6);
388 #ifdef ISC_PLATFORM_HAVESALEN
389 		sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
390 #endif
391 		memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
392 #ifdef ISC_PLATFORM_HAVESCOPEID
393 		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
394 #endif
395 		sockaddr->type.sin6.sin6_port = htons(port);
396 		break;
397 	default:
398 		INSIST(0);
399 	}
400 	ISC_LINK_INIT(sockaddr, link);
401 }
402 
403 void
isc_sockaddr_setport(isc_sockaddr_t * sockaddr,in_port_t port)404 isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
405 	switch (sockaddr->type.sa.sa_family) {
406 	case AF_INET:
407 		sockaddr->type.sin.sin_port = htons(port);
408 		break;
409 	case AF_INET6:
410 		sockaddr->type.sin6.sin6_port = htons(port);
411 		break;
412 	default:
413 		FATAL_ERROR(__FILE__, __LINE__,
414 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
415 					   ISC_MSG_UNKNOWNFAMILY,
416 					   "unknown address family: %d"),
417 			    (int)sockaddr->type.sa.sa_family);
418 	}
419 }
420 
421 in_port_t
isc_sockaddr_getport(const isc_sockaddr_t * sockaddr)422 isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
423 	in_port_t port = 0;
424 
425 	switch (sockaddr->type.sa.sa_family) {
426 	case AF_INET:
427 		port = ntohs(sockaddr->type.sin.sin_port);
428 		break;
429 	case AF_INET6:
430 		port = ntohs(sockaddr->type.sin6.sin6_port);
431 		break;
432 	default:
433 		FATAL_ERROR(__FILE__, __LINE__,
434 			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
435 					   ISC_MSG_UNKNOWNFAMILY,
436 					   "unknown address family: %d"),
437 			    (int)sockaddr->type.sa.sa_family);
438 	}
439 
440 	return (port);
441 }
442 
443 isc_boolean_t
isc_sockaddr_ismulticast(const isc_sockaddr_t * sockaddr)444 isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
445 	isc_netaddr_t netaddr;
446 
447 	if (sockaddr->type.sa.sa_family == AF_INET ||
448 	    sockaddr->type.sa.sa_family == AF_INET6) {
449 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
450 		return (isc_netaddr_ismulticast(&netaddr));
451 	}
452 	return (ISC_FALSE);
453 }
454 
455 isc_boolean_t
isc_sockaddr_isexperimental(const isc_sockaddr_t * sockaddr)456 isc_sockaddr_isexperimental(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_isexperimental(&netaddr));
462 	}
463 	return (ISC_FALSE);
464 }
465 
466 isc_boolean_t
isc_sockaddr_issitelocal(const isc_sockaddr_t * sockaddr)467 isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
468 	isc_netaddr_t netaddr;
469 
470 	if (sockaddr->type.sa.sa_family == AF_INET6) {
471 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
472 		return (isc_netaddr_issitelocal(&netaddr));
473 	}
474 	return (ISC_FALSE);
475 }
476 
477 isc_boolean_t
isc_sockaddr_islinklocal(const isc_sockaddr_t * sockaddr)478 isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
479 	isc_netaddr_t netaddr;
480 
481 	if (sockaddr->type.sa.sa_family == AF_INET6) {
482 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
483 		return (isc_netaddr_islinklocal(&netaddr));
484 	}
485 	return (ISC_FALSE);
486 }
487 
488 isc_result_t
isc_sockaddr_frompath(isc_sockaddr_t * sockaddr,const char * path)489 isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
490 #ifdef ISC_PLATFORM_HAVESYSUNH
491 	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
492 		return (ISC_R_NOSPACE);
493 	memset(sockaddr, 0, sizeof(*sockaddr));
494 	sockaddr->length = sizeof(sockaddr->type.sunix);
495 	sockaddr->type.sunix.sun_family = AF_UNIX;
496 #ifdef ISC_PLATFORM_HAVESALEN
497 	sockaddr->type.sunix.sun_len =
498 			(unsigned char)sizeof(sockaddr->type.sunix);
499 #endif
500 	strcpy(sockaddr->type.sunix.sun_path, path);
501 	return (ISC_R_SUCCESS);
502 #else
503 	UNUSED(sockaddr);
504 	UNUSED(path);
505 	return (ISC_R_NOTIMPLEMENTED);
506 #endif
507 }
508