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