1/*
2 * Copyright (C) 2004, 2005, 2007, 2010-2012  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002  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/msgs.h>
28#include <isc/net.h>
29#include <isc/netaddr.h>
30#include <isc/print.h>
31#include <isc/sockaddr.h>
32#include <isc/string.h>
33#include <isc/util.h>
34
35isc_boolean_t
36isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
37	REQUIRE(a != NULL && b != NULL);
38
39	if (a->family != b->family)
40		return (ISC_FALSE);
41
42	if (a->zone != b->zone)
43		return (ISC_FALSE);
44
45	switch (a->family) {
46	case AF_INET:
47		if (a->type.in.s_addr != b->type.in.s_addr)
48			return (ISC_FALSE);
49		break;
50	case AF_INET6:
51		if (memcmp(&a->type.in6, &b->type.in6,
52			   sizeof(a->type.in6)) != 0 ||
53		    a->zone != b->zone)
54			return (ISC_FALSE);
55		break;
56#ifdef ISC_PLATFORM_HAVESYSUNH
57	case AF_UNIX:
58		if (strcmp(a->type.un, b->type.un) != 0)
59			return (ISC_FALSE);
60		break;
61#endif
62	default:
63		return (ISC_FALSE);
64	}
65	return (ISC_TRUE);
66}
67
68isc_boolean_t
69isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
70		     unsigned int prefixlen)
71{
72	const unsigned char *pa = NULL, *pb = NULL;
73	unsigned int ipabytes = 0; /* Length of whole IP address in bytes */
74	unsigned int nbytes;       /* Number of significant whole bytes */
75	unsigned int nbits;        /* Number of significant leftover bits */
76
77	REQUIRE(a != NULL && b != NULL);
78
79	if (a->family != b->family)
80		return (ISC_FALSE);
81
82	if (a->zone != b->zone && b->zone != 0)
83		return (ISC_FALSE);
84
85	switch (a->family) {
86	case AF_INET:
87		pa = (const unsigned char *) &a->type.in;
88		pb = (const unsigned char *) &b->type.in;
89		ipabytes = 4;
90		break;
91	case AF_INET6:
92		pa = (const unsigned char *) &a->type.in6;
93		pb = (const unsigned char *) &b->type.in6;
94		ipabytes = 16;
95		break;
96	default:
97		return (ISC_FALSE);
98	}
99
100	/*
101	 * Don't crash if we get a pattern like 10.0.0.1/9999999.
102	 */
103	if (prefixlen > ipabytes * 8)
104		prefixlen = ipabytes * 8;
105
106	nbytes = prefixlen / 8;
107	nbits = prefixlen % 8;
108
109	if (nbytes > 0) {
110		if (memcmp(pa, pb, nbytes) != 0)
111			return (ISC_FALSE);
112	}
113	if (nbits > 0) {
114		unsigned int bytea, byteb, mask;
115		INSIST(nbytes < ipabytes);
116		INSIST(nbits < 8);
117		bytea = pa[nbytes];
118		byteb = pb[nbytes];
119		mask = (0xFF << (8-nbits)) & 0xFF;
120		if ((bytea & mask) != (byteb & mask))
121			return (ISC_FALSE);
122	}
123	return (ISC_TRUE);
124}
125
126isc_result_t
127isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
128	char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
129	char zbuf[sizeof("%4294967295")];
130	unsigned int alen;
131	int zlen;
132	const char *r;
133	const void *type;
134
135	REQUIRE(netaddr != NULL);
136
137	switch (netaddr->family) {
138	case AF_INET:
139		type = &netaddr->type.in;
140		break;
141	case AF_INET6:
142		type = &netaddr->type.in6;
143		break;
144#ifdef ISC_PLATFORM_HAVESYSUNH
145	case AF_UNIX:
146		alen = strlen(netaddr->type.un);
147		if (alen > isc_buffer_availablelength(target))
148			return (ISC_R_NOSPACE);
149		isc_buffer_putmem(target,
150				  (const unsigned char *)(netaddr->type.un),
151				  alen);
152		return (ISC_R_SUCCESS);
153#endif
154	default:
155		return (ISC_R_FAILURE);
156	}
157	r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
158	if (r == NULL)
159		return (ISC_R_FAILURE);
160
161	alen = strlen(abuf);
162	INSIST(alen < sizeof(abuf));
163
164	zlen = 0;
165	if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
166		zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
167		if (zlen < 0)
168			return (ISC_R_FAILURE);
169		INSIST((unsigned int)zlen < sizeof(zbuf));
170	}
171
172	if (alen + zlen > isc_buffer_availablelength(target))
173		return (ISC_R_NOSPACE);
174
175	isc_buffer_putmem(target, (unsigned char *)abuf, alen);
176	isc_buffer_putmem(target, (unsigned char *)zbuf, zlen);
177
178	return (ISC_R_SUCCESS);
179}
180
181void
182isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
183	isc_result_t result;
184	isc_buffer_t buf;
185
186	isc_buffer_init(&buf, array, size);
187	result = isc_netaddr_totext(na, &buf);
188
189	if (size == 0)
190		return;
191
192	/*
193	 * Null terminate.
194	 */
195	if (result == ISC_R_SUCCESS) {
196		if (isc_buffer_availablelength(&buf) >= 1)
197			isc_buffer_putuint8(&buf, 0);
198		else
199			result = ISC_R_NOSPACE;
200	}
201
202	if (result != ISC_R_SUCCESS) {
203		snprintf(array, size,
204			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
205					ISC_MSG_UNKNOWNADDR,
206					"<unknown address, family %u>"),
207			 na->family);
208		array[size - 1] = '\0';
209	}
210}
211
212
213isc_result_t
214isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
215	static const unsigned char zeros[16];
216	unsigned int nbits, nbytes, ipbytes = 0;
217	const unsigned char *p;
218
219	switch (na->family) {
220	case AF_INET:
221		p = (const unsigned char *) &na->type.in;
222		ipbytes = 4;
223		if (prefixlen > 32)
224			return (ISC_R_RANGE);
225		break;
226	case AF_INET6:
227		p = (const unsigned char *) &na->type.in6;
228		ipbytes = 16;
229		if (prefixlen > 128)
230			return (ISC_R_RANGE);
231		break;
232	default:
233		return (ISC_R_NOTIMPLEMENTED);
234	}
235	nbytes = prefixlen / 8;
236	nbits = prefixlen % 8;
237	if (nbits != 0) {
238		if ((p[nbytes] & (0xff>>nbits)) != 0U)
239			return (ISC_R_FAILURE);
240		nbytes++;
241	}
242	if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
243		return (ISC_R_FAILURE);
244	return (ISC_R_SUCCESS);
245}
246
247isc_result_t
248isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
249	unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
250	const unsigned char *p;
251
252	switch (s->family) {
253	case AF_INET:
254		p = (const unsigned char *) &s->type.in;
255		ipbytes = 4;
256		break;
257	case AF_INET6:
258		p = (const unsigned char *) &s->type.in6;
259		ipbytes = 16;
260		break;
261	default:
262		return (ISC_R_NOTIMPLEMENTED);
263	}
264	for (i = 0; i < ipbytes; i++) {
265		if (p[i] != 0xFF)
266			break;
267	}
268	nbytes = i;
269	if (i < ipbytes) {
270		unsigned int c = p[nbytes];
271		while ((c & 0x80) != 0 && nbits < 8) {
272			c <<= 1; nbits++;
273		}
274		if ((c & 0xFF) != 0)
275			return (ISC_R_MASKNONCONTIG);
276		i++;
277	}
278	for (; i < ipbytes; i++) {
279		if (p[i] != 0)
280			return (ISC_R_MASKNONCONTIG);
281		i++;
282	}
283	*lenp = nbytes * 8 + nbits;
284	return (ISC_R_SUCCESS);
285}
286
287void
288isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
289	memset(netaddr, 0, sizeof(*netaddr));
290	netaddr->family = AF_INET;
291	netaddr->type.in = *ina;
292}
293
294void
295isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
296	memset(netaddr, 0, sizeof(*netaddr));
297	netaddr->family = AF_INET6;
298	netaddr->type.in6 = *ina6;
299}
300
301isc_result_t
302isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
303#ifdef ISC_PLATFORM_HAVESYSUNH
304	if (strlen(path) > sizeof(netaddr->type.un) - 1)
305		return (ISC_R_NOSPACE);
306
307	memset(netaddr, 0, sizeof(*netaddr));
308	netaddr->family = AF_UNIX;
309	strcpy(netaddr->type.un, path);
310	netaddr->zone = 0;
311	return (ISC_R_SUCCESS);
312#else
313	UNUSED(netaddr);
314	UNUSED(path);
315	return (ISC_R_NOTIMPLEMENTED);
316#endif
317}
318
319
320void
321isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) {
322	/* we currently only support AF_INET6. */
323	REQUIRE(netaddr->family == AF_INET6);
324
325	netaddr->zone = zone;
326}
327
328isc_uint32_t
329isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
330	return (netaddr->zone);
331}
332
333void
334isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
335	int family = s->type.sa.sa_family;
336	t->family = family;
337	switch (family) {
338	case AF_INET:
339		t->type.in = s->type.sin.sin_addr;
340		t->zone = 0;
341		break;
342	case AF_INET6:
343		memcpy(&t->type.in6, &s->type.sin6.sin6_addr, 16);
344#ifdef ISC_PLATFORM_HAVESCOPEID
345		t->zone = s->type.sin6.sin6_scope_id;
346#else
347		t->zone = 0;
348#endif
349		break;
350#ifdef ISC_PLATFORM_HAVESYSUNH
351	case AF_UNIX:
352		memcpy(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
353		t->zone = 0;
354		break;
355#endif
356	default:
357		INSIST(0);
358	}
359}
360
361void
362isc_netaddr_any(isc_netaddr_t *netaddr) {
363	memset(netaddr, 0, sizeof(*netaddr));
364	netaddr->family = AF_INET;
365	netaddr->type.in.s_addr = INADDR_ANY;
366}
367
368void
369isc_netaddr_any6(isc_netaddr_t *netaddr) {
370	memset(netaddr, 0, sizeof(*netaddr));
371	netaddr->family = AF_INET6;
372	netaddr->type.in6 = in6addr_any;
373}
374
375isc_boolean_t
376isc_netaddr_ismulticast(isc_netaddr_t *na) {
377	switch (na->family) {
378	case AF_INET:
379		return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr)));
380	case AF_INET6:
381		return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6)));
382	default:
383		return (ISC_FALSE);  /* XXXMLG ? */
384	}
385}
386
387isc_boolean_t
388isc_netaddr_isexperimental(isc_netaddr_t *na) {
389	switch (na->family) {
390	case AF_INET:
391		return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr)));
392	default:
393		return (ISC_FALSE);  /* XXXMLG ? */
394	}
395}
396
397isc_boolean_t
398isc_netaddr_islinklocal(isc_netaddr_t *na) {
399	switch (na->family) {
400	case AF_INET:
401		return (ISC_FALSE);
402	case AF_INET6:
403		return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6)));
404	default:
405		return (ISC_FALSE);
406	}
407}
408
409isc_boolean_t
410isc_netaddr_issitelocal(isc_netaddr_t *na) {
411	switch (na->family) {
412	case AF_INET:
413		return (ISC_FALSE);
414	case AF_INET6:
415		return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6)));
416	default:
417		return (ISC_FALSE);
418	}
419}
420
421void
422isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
423	isc_netaddr_t *src;
424
425	DE_CONST(s, src);	/* Must come before IN6_IS_ADDR_V4MAPPED. */
426
427	REQUIRE(s->family == AF_INET6);
428	REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
429
430	memset(t, 0, sizeof(*t));
431	t->family = AF_INET;
432	memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4);
433	return;
434}
435