sockaddr.c revision 1.5
1/*	$NetBSD: sockaddr.c,v 1.5 2015/04/07 17:34:18 christos Exp $	*/
2
3/*
4 * Copyright (C) 2004-2007, 2010-2012  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
38isc_boolean_t
39isc_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
45isc_boolean_t
46isc_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
51isc_boolean_t
52isc_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
105isc_boolean_t
106isc_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
115isc_result_t
116isc_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
182void
183isc_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			 "<%s %u>",
198			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
199					ISC_MSG_UNKNOWNADDR,
200					"unknown address, family"),
201			 sa->type.sa.sa_family);
202		array[size - 1] = '\0';
203	}
204}
205
206unsigned int
207isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
208	unsigned int length = 0;
209	const unsigned char *s = NULL;
210	unsigned int h = 0;
211	unsigned int g;
212	unsigned int p = 0;
213	const struct in6_addr *in6;
214
215	REQUIRE(sockaddr != NULL);
216
217	switch (sockaddr->type.sa.sa_family) {
218	case AF_INET:
219		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
220		p = ntohs(sockaddr->type.sin.sin_port);
221		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
222		break;
223	case AF_INET6:
224		in6 = &sockaddr->type.sin6.sin6_addr;
225		if (IN6_IS_ADDR_V4MAPPED(in6)) {
226			s = (const unsigned char *)&in6 + 12;
227			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
228		} else {
229			s = (const unsigned char *)in6;
230			length = sizeof(sockaddr->type.sin6.sin6_addr);
231		}
232		p = ntohs(sockaddr->type.sin6.sin6_port);
233		break;
234	default:
235		UNEXPECTED_ERROR(__FILE__, __LINE__,
236				 "%s: %d",
237				 isc_msgcat_get(isc_msgcat,
238						ISC_MSGSET_SOCKADDR,
239						ISC_MSG_UNKNOWNFAMILY,
240						"unknown address family"),
241					     (int)sockaddr->type.sa.sa_family);
242		s = (const unsigned char *)&sockaddr->type;
243		length = sockaddr->length;
244		p = 0;
245	}
246
247	h = isc_hash_calc(s, length, ISC_TRUE);
248	if (!address_only) {
249		g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
250				  ISC_TRUE);
251		h = h ^ g; /* XXX: we should concatenate h and p first */
252	}
253
254	return (h);
255}
256
257void
258isc_sockaddr_any(isc_sockaddr_t *sockaddr)
259{
260	memset(sockaddr, 0, sizeof(*sockaddr));
261	sockaddr->type.sin.sin_family = AF_INET;
262#ifdef ISC_PLATFORM_HAVESALEN
263	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
264#endif
265	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
266	sockaddr->type.sin.sin_port = 0;
267	sockaddr->length = sizeof(sockaddr->type.sin);
268	ISC_LINK_INIT(sockaddr, link);
269}
270
271void
272isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
273{
274	memset(sockaddr, 0, sizeof(*sockaddr));
275	sockaddr->type.sin6.sin6_family = AF_INET6;
276#ifdef ISC_PLATFORM_HAVESALEN
277	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
278#endif
279	sockaddr->type.sin6.sin6_addr = in6addr_any;
280	sockaddr->type.sin6.sin6_port = 0;
281	sockaddr->length = sizeof(sockaddr->type.sin6);
282	ISC_LINK_INIT(sockaddr, link);
283}
284
285void
286isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
287		    in_port_t port)
288{
289	memset(sockaddr, 0, sizeof(*sockaddr));
290	sockaddr->type.sin.sin_family = AF_INET;
291#ifdef ISC_PLATFORM_HAVESALEN
292	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
293#endif
294	sockaddr->type.sin.sin_addr = *ina;
295	sockaddr->type.sin.sin_port = htons(port);
296	sockaddr->length = sizeof(sockaddr->type.sin);
297	ISC_LINK_INIT(sockaddr, link);
298}
299
300void
301isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
302     switch (pf) {
303     case AF_INET:
304	     isc_sockaddr_any(sockaddr);
305	     break;
306     case AF_INET6:
307	     isc_sockaddr_any6(sockaddr);
308	     break;
309     default:
310	     INSIST(0);
311     }
312}
313
314void
315isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
316		     in_port_t port)
317{
318	memset(sockaddr, 0, sizeof(*sockaddr));
319	sockaddr->type.sin6.sin6_family = AF_INET6;
320#ifdef ISC_PLATFORM_HAVESALEN
321	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
322#endif
323	sockaddr->type.sin6.sin6_addr = *ina6;
324	sockaddr->type.sin6.sin6_port = htons(port);
325	sockaddr->length = sizeof(sockaddr->type.sin6);
326	ISC_LINK_INIT(sockaddr, link);
327}
328
329void
330isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
331		      in_port_t port)
332{
333	memset(sockaddr, 0, sizeof(*sockaddr));
334	sockaddr->type.sin6.sin6_family = AF_INET6;
335#ifdef ISC_PLATFORM_HAVESALEN
336	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
337#endif
338	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
339	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
340	memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
341	sockaddr->type.sin6.sin6_port = htons(port);
342	sockaddr->length = sizeof(sockaddr->type.sin6);
343	ISC_LINK_INIT(sockaddr, link);
344}
345
346int
347isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
348
349	/*
350	 * Get the protocol family of 'sockaddr'.
351	 */
352
353#if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
354	/*
355	 * Assume that PF_xxx == AF_xxx for all AF and PF.
356	 */
357	return (sockaddr->type.sa.sa_family);
358#else
359	switch (sockaddr->type.sa.sa_family) {
360	case AF_INET:
361		return (PF_INET);
362	case AF_INET6:
363		return (PF_INET6);
364	default:
365		FATAL_ERROR(__FILE__, __LINE__,
366			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
367					   ISC_MSG_UNKNOWNFAMILY,
368					   "unknown address family: %d"),
369			    (int)sockaddr->type.sa.sa_family);
370	}
371#endif
372}
373
374void
375isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
376		    in_port_t port)
377{
378	memset(sockaddr, 0, sizeof(*sockaddr));
379	sockaddr->type.sin.sin_family = (short)na->family;
380	switch (na->family) {
381	case AF_INET:
382		sockaddr->length = sizeof(sockaddr->type.sin);
383#ifdef ISC_PLATFORM_HAVESALEN
384		sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
385#endif
386		sockaddr->type.sin.sin_addr = na->type.in;
387		sockaddr->type.sin.sin_port = htons(port);
388		break;
389	case AF_INET6:
390		sockaddr->length = sizeof(sockaddr->type.sin6);
391#ifdef ISC_PLATFORM_HAVESALEN
392		sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
393#endif
394		memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
395#ifdef ISC_PLATFORM_HAVESCOPEID
396		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
397#endif
398		sockaddr->type.sin6.sin6_port = htons(port);
399		break;
400	default:
401		INSIST(0);
402	}
403	ISC_LINK_INIT(sockaddr, link);
404}
405
406void
407isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
408	switch (sockaddr->type.sa.sa_family) {
409	case AF_INET:
410		sockaddr->type.sin.sin_port = htons(port);
411		break;
412	case AF_INET6:
413		sockaddr->type.sin6.sin6_port = htons(port);
414		break;
415	default:
416		FATAL_ERROR(__FILE__, __LINE__,
417			    "%s: %d",
418			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
419					   ISC_MSG_UNKNOWNFAMILY,
420					   "unknown address family"),
421			    (int)sockaddr->type.sa.sa_family);
422	}
423}
424
425in_port_t
426isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
427	in_port_t port = 0;
428
429	switch (sockaddr->type.sa.sa_family) {
430	case AF_INET:
431		port = ntohs(sockaddr->type.sin.sin_port);
432		break;
433	case AF_INET6:
434		port = ntohs(sockaddr->type.sin6.sin6_port);
435		break;
436	default:
437		FATAL_ERROR(__FILE__, __LINE__,
438			    "%s: %d",
439			    isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
440					   ISC_MSG_UNKNOWNFAMILY,
441					   "unknown address family"),
442			    (int)sockaddr->type.sa.sa_family);
443	}
444
445	return (port);
446}
447
448isc_boolean_t
449isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
450	isc_netaddr_t netaddr;
451
452	if (sockaddr->type.sa.sa_family == AF_INET ||
453	    sockaddr->type.sa.sa_family == AF_INET6) {
454		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
455		return (isc_netaddr_ismulticast(&netaddr));
456	}
457	return (ISC_FALSE);
458}
459
460isc_boolean_t
461isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
462	isc_netaddr_t netaddr;
463
464	if (sockaddr->type.sa.sa_family == AF_INET) {
465		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
466		return (isc_netaddr_isexperimental(&netaddr));
467	}
468	return (ISC_FALSE);
469}
470
471isc_boolean_t
472isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
473	isc_netaddr_t netaddr;
474
475	if (sockaddr->type.sa.sa_family == AF_INET6) {
476		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
477		return (isc_netaddr_issitelocal(&netaddr));
478	}
479	return (ISC_FALSE);
480}
481
482isc_boolean_t
483isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
484	isc_netaddr_t netaddr;
485
486	if (sockaddr->type.sa.sa_family == AF_INET6) {
487		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
488		return (isc_netaddr_islinklocal(&netaddr));
489	}
490	return (ISC_FALSE);
491}
492
493isc_result_t
494isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
495#ifdef ISC_PLATFORM_HAVESYSUNH
496	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
497		return (ISC_R_NOSPACE);
498	memset(sockaddr, 0, sizeof(*sockaddr));
499	sockaddr->length = sizeof(sockaddr->type.sunix);
500	sockaddr->type.sunix.sun_family = AF_UNIX;
501#ifdef ISC_PLATFORM_HAVESALEN
502	sockaddr->type.sunix.sun_len =
503			(unsigned char)sizeof(sockaddr->type.sunix);
504#endif
505	strcpy(sockaddr->type.sunix.sun_path, path);
506	return (ISC_R_SUCCESS);
507#else
508	UNUSED(sockaddr);
509	UNUSED(path);
510	return (ISC_R_NOTIMPLEMENTED);
511#endif
512}
513