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