1181834Sroberto/*
2181834Sroberto * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3181834Sroberto * Copyright (C) 1999-2002  Internet Software Consortium.
4181834Sroberto *
5181834Sroberto * Permission to use, copy, modify, and distribute this software for any
6181834Sroberto * purpose with or without fee is hereby granted, provided that the above
7181834Sroberto * copyright notice and this permission notice appear in all copies.
8181834Sroberto *
9181834Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10181834Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11181834Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12181834Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13181834Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14181834Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15181834Sroberto * PERFORMANCE OF THIS SOFTWARE.
16181834Sroberto */
17181834Sroberto
18181834Sroberto/* $Id: netaddr.c,v 1.18.12.9 2004/05/15 03:46:12 jinmei Exp $ */
19181834Sroberto
20181834Sroberto#include <config.h>
21181834Sroberto
22181834Sroberto#define ISC_ONLY_IPV6
23181834Sroberto
24181834Sroberto#include <stdio.h>
25181834Sroberto
26181834Sroberto#include <isc/buffer.h>
27181834Sroberto#include <isc/msgs.h>
28181834Sroberto#include <isc/net.h>
29181834Sroberto#include <isc/netaddr.h>
30181834Sroberto#include <isc/print.h>
31181834Sroberto#include <isc/sockaddr.h>
32181834Sroberto#include <isc/string.h>
33181834Sroberto#include <isc/util.h>
34181834Sroberto
35181834Srobertoisc_boolean_t
36181834Srobertoisc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
37181834Sroberto	REQUIRE(a != NULL && b != NULL);
38181834Sroberto
39181834Sroberto	if (a->family != b->family)
40181834Sroberto		return (ISC_FALSE);
41181834Sroberto
42181834Sroberto	if (a->zone != b->zone)
43181834Sroberto		return (ISC_FALSE);
44181834Sroberto
45181834Sroberto	switch (a->family) {
46181834Sroberto	case AF_INET:
47181834Sroberto		if (a->type.in.s_addr != b->type.in.s_addr)
48181834Sroberto			return (ISC_FALSE);
49181834Sroberto		break;
50181834Sroberto	case AF_INET6:
51181834Sroberto		if (memcmp(&a->type.in6, &b->type.in6,
52181834Sroberto			   sizeof(a->type.in6)) != 0 ||
53181834Sroberto		    a->zone != b->zone)
54181834Sroberto			return (ISC_FALSE);
55181834Sroberto		break;
56181834Sroberto	default:
57181834Sroberto		return (ISC_FALSE);
58181834Sroberto	}
59181834Sroberto	return (ISC_TRUE);
60181834Sroberto}
61181834Sroberto
62181834Srobertoisc_boolean_t
63181834Srobertoisc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
64181834Sroberto		     unsigned int prefixlen)
65181834Sroberto{
66181834Sroberto	const unsigned char *pa, *pb;
67181834Sroberto	unsigned int ipabytes; /* Length of whole IP address in bytes */
68181834Sroberto	unsigned int nbytes;   /* Number of significant whole bytes */
69181834Sroberto	unsigned int nbits;    /* Number of significant leftover bits */
70181834Sroberto
71181834Sroberto	REQUIRE(a != NULL && b != NULL);
72181834Sroberto
73181834Sroberto	if (a->family != b->family)
74181834Sroberto		return (ISC_FALSE);
75181834Sroberto
76181834Sroberto	if (a->zone != b->zone)
77181834Sroberto		return (ISC_FALSE);
78181834Sroberto
79181834Sroberto	switch (a->family) {
80181834Sroberto	case AF_INET:
81181834Sroberto		pa = (const unsigned char *) &a->type.in;
82181834Sroberto		pb = (const unsigned char *) &b->type.in;
83181834Sroberto		ipabytes = 4;
84181834Sroberto		break;
85181834Sroberto	case AF_INET6:
86181834Sroberto		pa = (const unsigned char *) &a->type.in6;
87181834Sroberto		pb = (const unsigned char *) &b->type.in6;
88181834Sroberto		ipabytes = 16;
89181834Sroberto		break;
90181834Sroberto	default:
91181834Sroberto		pa = pb = NULL; /* Avoid silly compiler warning. */
92181834Sroberto		ipabytes = 0; /* Ditto. */
93181834Sroberto		return (ISC_FALSE);
94181834Sroberto	}
95181834Sroberto
96181834Sroberto	/*
97181834Sroberto	 * Don't crash if we get a pattern like 10.0.0.1/9999999.
98181834Sroberto	 */
99181834Sroberto	if (prefixlen > ipabytes * 8)
100181834Sroberto		prefixlen = ipabytes * 8;
101181834Sroberto
102181834Sroberto	nbytes = prefixlen / 8;
103181834Sroberto	nbits = prefixlen % 8;
104181834Sroberto
105181834Sroberto	if (nbytes > 0) {
106181834Sroberto		if (memcmp(pa, pb, nbytes) != 0)
107181834Sroberto			return (ISC_FALSE);
108181834Sroberto	}
109181834Sroberto	if (nbits > 0) {
110181834Sroberto		unsigned int bytea, byteb, mask;
111181834Sroberto		INSIST(nbytes < ipabytes);
112181834Sroberto		INSIST(nbits < 8);
113181834Sroberto		bytea = pa[nbytes];
114181834Sroberto		byteb = pb[nbytes];
115181834Sroberto		mask = (0xFF << (8-nbits)) & 0xFF;
116181834Sroberto		if ((bytea & mask) != (byteb & mask))
117181834Sroberto			return (ISC_FALSE);
118181834Sroberto	}
119181834Sroberto	return (ISC_TRUE);
120181834Sroberto}
121181834Sroberto
122181834Srobertoisc_result_t
123181834Srobertoisc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
124181834Sroberto	char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
125181834Sroberto	char zbuf[sizeof("%4294967295")];
126181834Sroberto	unsigned int alen;
127181834Sroberto	int zlen;
128181834Sroberto	const char *r;
129181834Sroberto	const void *type;
130181834Sroberto
131181834Sroberto	REQUIRE(netaddr != NULL);
132181834Sroberto
133181834Sroberto	switch (netaddr->family) {
134181834Sroberto	case AF_INET:
135181834Sroberto		type = &netaddr->type.in;
136181834Sroberto		break;
137181834Sroberto	case AF_INET6:
138181834Sroberto		type = &netaddr->type.in6;
139181834Sroberto		break;
140181834Sroberto	default:
141181834Sroberto		return (ISC_R_FAILURE);
142181834Sroberto	}
143181834Sroberto	r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
144181834Sroberto	if (r == NULL)
145181834Sroberto		return (ISC_R_FAILURE);
146181834Sroberto
147181834Sroberto	alen = strlen(abuf);
148181834Sroberto	INSIST(alen < sizeof(abuf));
149181834Sroberto
150181834Sroberto	zlen = 0;
151181834Sroberto	if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
152181834Sroberto		zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
153181834Sroberto		if (zlen < 0)
154181834Sroberto			return (ISC_R_FAILURE);
155181834Sroberto		INSIST((unsigned int)zlen < sizeof(zbuf));
156181834Sroberto	}
157181834Sroberto
158181834Sroberto	if (alen + zlen > isc_buffer_availablelength(target))
159181834Sroberto		return (ISC_R_NOSPACE);
160181834Sroberto
161181834Sroberto	isc_buffer_putmem(target, (unsigned char *)abuf, alen);
162181834Sroberto	isc_buffer_putmem(target, (unsigned char *)zbuf, zlen);
163181834Sroberto
164181834Sroberto	return (ISC_R_SUCCESS);
165181834Sroberto}
166181834Sroberto
167181834Srobertovoid
168181834Srobertoisc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
169181834Sroberto	isc_result_t result;
170181834Sroberto	isc_buffer_t buf;
171181834Sroberto
172181834Sroberto	isc_buffer_init(&buf, array, size);
173181834Sroberto	result = isc_netaddr_totext(na, &buf);
174181834Sroberto
175181834Sroberto	/*
176181834Sroberto	 * Null terminate.
177181834Sroberto	 */
178181834Sroberto	if (result == ISC_R_SUCCESS) {
179181834Sroberto		if (isc_buffer_availablelength(&buf) >= 1)
180181834Sroberto			isc_buffer_putuint8(&buf, 0);
181181834Sroberto		else
182181834Sroberto			result = ISC_R_NOSPACE;
183181834Sroberto	}
184181834Sroberto
185181834Sroberto	if (result != ISC_R_SUCCESS) {
186181834Sroberto		snprintf(array, size,
187181834Sroberto			 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
188181834Sroberto					ISC_MSG_UNKNOWNADDR,
189181834Sroberto					"<unknown address, family %u>"),
190181834Sroberto			 na->family);
191181834Sroberto		array[size - 1] = '\0';
192181834Sroberto	}
193181834Sroberto}
194181834Sroberto
195181834Srobertoisc_result_t
196181834Srobertoisc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
197181834Sroberto	unsigned int nbits, nbytes, ipbytes, i;
198181834Sroberto	const unsigned char *p;
199181834Sroberto
200181834Sroberto	switch (s->family) {
201181834Sroberto	case AF_INET:
202181834Sroberto		p = (const unsigned char *) &s->type.in;
203181834Sroberto		ipbytes = 4;
204181834Sroberto		break;
205181834Sroberto	case AF_INET6:
206181834Sroberto		p = (const unsigned char *) &s->type.in6;
207181834Sroberto		ipbytes = 16;
208181834Sroberto		break;
209181834Sroberto	default:
210181834Sroberto		ipbytes = 0;
211181834Sroberto		return (ISC_R_NOTIMPLEMENTED);
212181834Sroberto	}
213181834Sroberto	nbytes = nbits = 0;
214181834Sroberto	for (i = 0; i < ipbytes; i++) {
215181834Sroberto		if (p[i] != 0xFF)
216181834Sroberto			break;
217181834Sroberto	}
218181834Sroberto	nbytes = i;
219181834Sroberto	if (i < ipbytes) {
220181834Sroberto		unsigned int c = p[nbytes];
221181834Sroberto		while ((c & 0x80) != 0 && nbits < 8) {
222181834Sroberto			c <<= 1; nbits++;
223181834Sroberto		}
224181834Sroberto		if ((c & 0xFF) != 0)
225181834Sroberto			return (ISC_R_MASKNONCONTIG);
226181834Sroberto		i++;
227181834Sroberto	}
228181834Sroberto	for (; i < ipbytes; i++) {
229181834Sroberto		if (p[i] != 0)
230181834Sroberto			return (ISC_R_MASKNONCONTIG);
231181834Sroberto		i++;
232181834Sroberto	}
233181834Sroberto	*lenp = nbytes * 8 + nbits;
234181834Sroberto	return (ISC_R_SUCCESS);
235181834Sroberto}
236181834Sroberto
237181834Srobertovoid
238181834Srobertoisc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
239181834Sroberto	memset(netaddr, 0, sizeof(*netaddr));
240181834Sroberto	netaddr->family = AF_INET;
241181834Sroberto	netaddr->type.in = *ina;
242181834Sroberto}
243181834Sroberto
244181834Srobertovoid
245181834Srobertoisc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
246181834Sroberto	memset(netaddr, 0, sizeof(*netaddr));
247181834Sroberto	netaddr->family = AF_INET6;
248181834Sroberto	netaddr->type.in6 = *ina6;
249181834Sroberto}
250181834Sroberto
251181834Srobertovoid
252181834Srobertoisc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) {
253181834Sroberto	/* we currently only support AF_INET6. */
254181834Sroberto	REQUIRE(netaddr->family == AF_INET6);
255181834Sroberto
256181834Sroberto	netaddr->zone = zone;
257181834Sroberto}
258181834Sroberto
259181834Srobertoisc_uint32_t
260181834Srobertoisc_netaddr_getzone(const isc_netaddr_t *netaddr) {
261181834Sroberto	return (netaddr->zone);
262181834Sroberto}
263181834Sroberto
264181834Srobertovoid
265181834Srobertoisc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
266181834Sroberto	int family = s->type.sa.sa_family;
267181834Sroberto	t->family = family;
268181834Sroberto	switch (family) {
269181834Sroberto	case AF_INET:
270181834Sroberto		t->type.in = s->type.sin.sin_addr;
271181834Sroberto		t->zone = 0;
272181834Sroberto		break;
273181834Sroberto	case AF_INET6:
274181834Sroberto		memcpy(&t->type.in6, &s->type.sin6.sin6_addr, 16);
275181834Sroberto#ifdef ISC_PLATFORM_HAVESCOPEID
276181834Sroberto		t->zone = s->type.sin6.sin6_scope_id;
277181834Sroberto#else
278181834Sroberto		t->zone = 0;
279181834Sroberto#endif
280181834Sroberto		break;
281181834Sroberto	default:
282181834Sroberto		INSIST(0);
283181834Sroberto	}
284181834Sroberto}
285181834Sroberto
286181834Srobertovoid
287181834Srobertoisc_netaddr_any(isc_netaddr_t *netaddr) {
288181834Sroberto	memset(netaddr, 0, sizeof(*netaddr));
289181834Sroberto	netaddr->family = AF_INET;
290181834Sroberto	netaddr->type.in.s_addr = INADDR_ANY;
291181834Sroberto}
292181834Sroberto
293181834Sroberto#ifdef ISC_PLATFORM_HAVEIPV6
294181834Srobertovoid
295181834Srobertoisc_netaddr_any6(isc_netaddr_t *netaddr) {
296181834Sroberto	memset(netaddr, 0, sizeof(*netaddr));
297181834Sroberto	netaddr->family = AF_INET6;
298181834Sroberto	netaddr->type.in6 = in6addr_any;
299181834Sroberto}
300181834Sroberto#endif
301181834Sroberto
302181834Srobertoisc_boolean_t
303181834Srobertoisc_netaddr_ismulticast(isc_netaddr_t *na) {
304181834Sroberto	switch (na->family) {
305181834Sroberto	case AF_INET:
306181834Sroberto		return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr)));
307181834Sroberto	case AF_INET6:
308181834Sroberto		return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6)));
309181834Sroberto	default:
310181834Sroberto		return (ISC_FALSE);  /* XXXMLG ? */
311181834Sroberto	}
312181834Sroberto}
313181834Sroberto
314181834Srobertoisc_boolean_t
315181834Srobertoisc_netaddr_isexperimental(isc_netaddr_t *na) {
316181834Sroberto	switch (na->family) {
317181834Sroberto	case AF_INET:
318181834Sroberto		return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr)));
319181834Sroberto	default:
320181834Sroberto		return (ISC_FALSE);  /* XXXMLG ? */
321181834Sroberto	}
322181834Sroberto}
323181834Sroberto
324181834Srobertoisc_boolean_t
325181834Srobertoisc_netaddr_islinklocal(isc_netaddr_t *na) {
326181834Sroberto	switch (na->family) {
327181834Sroberto	case AF_INET:
328181834Sroberto		return (ISC_FALSE);
329181834Sroberto	case AF_INET6:
330181834Sroberto		return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6)));
331181834Sroberto	default:
332181834Sroberto		return (ISC_FALSE);
333181834Sroberto	}
334181834Sroberto}
335181834Sroberto
336181834Srobertoisc_boolean_t
337181834Srobertoisc_netaddr_issitelocal(isc_netaddr_t *na) {
338181834Sroberto	switch (na->family) {
339181834Sroberto	case AF_INET:
340181834Sroberto		return (ISC_FALSE);
341181834Sroberto	case AF_INET6:
342181834Sroberto		return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6)));
343181834Sroberto	default:
344181834Sroberto		return (ISC_FALSE);
345181834Sroberto	}
346181834Sroberto}
347181834Sroberto
348181834Sroberto#ifdef ISC_PLATFORM_HAVEIPV6
349181834Srobertovoid
350181834Srobertoisc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
351181834Sroberto	isc_netaddr_t *src;
352181834Sroberto
353181834Sroberto	DE_CONST(s, src);	/* Must come before IN6_IS_ADDR_V4MAPPED. */
354181834Sroberto
355181834Sroberto	REQUIRE(s->family == AF_INET6);
356181834Sroberto	REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
357181834Sroberto
358181834Sroberto	memset(t, 0, sizeof(*t));
359181834Sroberto	t->family = AF_INET;
360181834Sroberto	memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4);
361181834Sroberto	return;
362181834Sroberto}
363181834Sroberto#endif
364