4 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2002 Internet Software Consortium.
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.
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.
20 /* Id: netaddr.c,v 1.38 2007/06/18 23:47:44 tbox Exp */
28 #include <isc/buffer.h>
31 #include <isc/netaddr.h>
32 #include <isc/print.h>
33 #include <isc/sockaddr.h>
34 #include <isc/string.h>
38 isc_netaddr_equal(const isc_netaddr_t
*a
, const isc_netaddr_t
*b
) {
39 REQUIRE(a
!= NULL
&& b
!= NULL
);
41 if (a
->family
!= b
->family
)
44 if (a
->zone
!= b
->zone
)
49 if (a
->type
.in
.s_addr
!= b
->type
.in
.s_addr
)
53 if (memcmp(&a
->type
.in6
, &b
->type
.in6
,
54 sizeof(a
->type
.in6
)) != 0 ||
58 #ifdef ISC_PLATFORM_HAVESYSUNH
60 if (strcmp(a
->type
.un
, b
->type
.un
) != 0)
71 isc_netaddr_eqprefix(const isc_netaddr_t
*a
, const isc_netaddr_t
*b
,
72 unsigned int prefixlen
)
74 const unsigned char *pa
, *pb
;
75 unsigned int ipabytes
; /* Length of whole IP address in bytes */
76 unsigned int nbytes
; /* Number of significant whole bytes */
77 unsigned int nbits
; /* Number of significant leftover bits */
79 REQUIRE(a
!= NULL
&& b
!= NULL
);
81 if (a
->family
!= b
->family
)
84 if (a
->zone
!= b
->zone
&& b
->zone
!= 0)
89 pa
= (const unsigned char *) &a
->type
.in
;
90 pb
= (const unsigned char *) &b
->type
.in
;
94 pa
= (const unsigned char *) &a
->type
.in6
;
95 pb
= (const unsigned char *) &b
->type
.in6
;
99 pa
= pb
= NULL
; /* Avoid silly compiler warning. */
100 ipabytes
= 0; /* Ditto. */
105 * Don't crash if we get a pattern like 10.0.0.1/9999999.
107 if (prefixlen
> ipabytes
* 8)
108 prefixlen
= ipabytes
* 8;
110 nbytes
= prefixlen
/ 8;
111 nbits
= prefixlen
% 8;
114 if (memcmp(pa
, pb
, nbytes
) != 0)
118 unsigned int bytea
, byteb
, mask
;
119 INSIST(nbytes
< ipabytes
);
123 mask
= (0xFF << (8-nbits
)) & 0xFF;
124 if ((bytea
& mask
) != (byteb
& mask
))
131 isc_netaddr_totext(const isc_netaddr_t
*netaddr
, isc_buffer_t
*target
) {
132 char abuf
[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
133 char zbuf
[sizeof("%4294967295")];
139 REQUIRE(netaddr
!= NULL
);
141 switch (netaddr
->family
) {
143 type
= &netaddr
->type
.in
;
146 type
= &netaddr
->type
.in6
;
148 #ifdef ISC_PLATFORM_HAVESYSUNH
150 alen
= strlen(netaddr
->type
.un
);
151 if (alen
> isc_buffer_availablelength(target
))
152 return (ISC_R_NOSPACE
);
153 isc_buffer_putmem(target
,
154 (const unsigned char *)(netaddr
->type
.un
),
156 return (ISC_R_SUCCESS
);
159 return (ISC_R_FAILURE
);
161 r
= inet_ntop(netaddr
->family
, type
, abuf
, sizeof(abuf
));
163 return (ISC_R_FAILURE
);
166 INSIST(alen
< sizeof(abuf
));
169 if (netaddr
->family
== AF_INET6
&& netaddr
->zone
!= 0) {
170 zlen
= snprintf(zbuf
, sizeof(zbuf
), "%%%u", netaddr
->zone
);
172 return (ISC_R_FAILURE
);
173 INSIST((unsigned int)zlen
< sizeof(zbuf
));
176 if (alen
+ zlen
> isc_buffer_availablelength(target
))
177 return (ISC_R_NOSPACE
);
179 isc_buffer_putmem(target
, (unsigned char *)abuf
, alen
);
180 isc_buffer_putmem(target
, (unsigned char *)zbuf
, zlen
);
182 return (ISC_R_SUCCESS
);
186 isc_netaddr_format(const isc_netaddr_t
*na
, char *array
, unsigned int size
) {
190 isc_buffer_init(&buf
, array
, size
);
191 result
= isc_netaddr_totext(na
, &buf
);
196 if (result
== ISC_R_SUCCESS
) {
197 if (isc_buffer_availablelength(&buf
) >= 1)
198 isc_buffer_putuint8(&buf
, 0);
200 result
= ISC_R_NOSPACE
;
203 if (result
!= ISC_R_SUCCESS
) {
204 snprintf(array
, size
,
205 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_NETADDR
,
207 "<unknown address, family %u>"),
209 array
[size
- 1] = '\0';
215 isc_netaddr_prefixok(const isc_netaddr_t
*na
, unsigned int prefixlen
) {
216 static const unsigned char zeros
[16];
217 unsigned int nbits
, nbytes
, ipbytes
;
218 const unsigned char *p
;
220 switch (na
->family
) {
222 p
= (const unsigned char *) &na
->type
.in
;
225 return (ISC_R_RANGE
);
228 p
= (const unsigned char *) &na
->type
.in6
;
231 return (ISC_R_RANGE
);
235 return (ISC_R_NOTIMPLEMENTED
);
237 nbytes
= prefixlen
/ 8;
238 nbits
= prefixlen
% 8;
240 if ((p
[nbytes
] & (0xff>>nbits
)) != 0U)
241 return (ISC_R_FAILURE
);
244 if (memcmp(p
+ nbytes
, zeros
, ipbytes
- nbytes
) != 0)
245 return (ISC_R_FAILURE
);
246 return (ISC_R_SUCCESS
);
250 isc_netaddr_masktoprefixlen(const isc_netaddr_t
*s
, unsigned int *lenp
) {
251 unsigned int nbits
, nbytes
, ipbytes
, i
;
252 const unsigned char *p
;
256 p
= (const unsigned char *) &s
->type
.in
;
260 p
= (const unsigned char *) &s
->type
.in6
;
265 return (ISC_R_NOTIMPLEMENTED
);
268 for (i
= 0; i
< ipbytes
; i
++) {
274 unsigned int c
= p
[nbytes
];
275 while ((c
& 0x80) != 0 && nbits
< 8) {
279 return (ISC_R_MASKNONCONTIG
);
282 for (; i
< ipbytes
; i
++) {
284 return (ISC_R_MASKNONCONTIG
);
287 *lenp
= nbytes
* 8 + nbits
;
288 return (ISC_R_SUCCESS
);
292 isc_netaddr_fromin(isc_netaddr_t
*netaddr
, const struct in_addr
*ina
) {
293 memset(netaddr
, 0, sizeof(*netaddr
));
294 netaddr
->family
= AF_INET
;
295 netaddr
->type
.in
= *ina
;
299 isc_netaddr_fromin6(isc_netaddr_t
*netaddr
, const struct in6_addr
*ina6
) {
300 memset(netaddr
, 0, sizeof(*netaddr
));
301 netaddr
->family
= AF_INET6
;
302 netaddr
->type
.in6
= *ina6
;
306 isc_netaddr_frompath(isc_netaddr_t
*netaddr
, const char *path
) {
307 #ifdef ISC_PLATFORM_HAVESYSUNH
308 if (strlen(path
) > sizeof(netaddr
->type
.un
) - 1)
309 return (ISC_R_NOSPACE
);
311 memset(netaddr
, 0, sizeof(*netaddr
));
312 netaddr
->family
= AF_UNIX
;
313 strcpy(netaddr
->type
.un
, path
);
315 return (ISC_R_SUCCESS
);
319 return (ISC_R_NOTIMPLEMENTED
);
325 isc_netaddr_setzone(isc_netaddr_t
*netaddr
, isc_uint32_t zone
) {
326 /* we currently only support AF_INET6. */
327 REQUIRE(netaddr
->family
== AF_INET6
);
329 netaddr
->zone
= zone
;
333 isc_netaddr_getzone(const isc_netaddr_t
*netaddr
) {
334 return (netaddr
->zone
);
338 isc_netaddr_fromsockaddr(isc_netaddr_t
*t
, const isc_sockaddr_t
*s
) {
339 int family
= s
->type
.sa
.sa_family
;
343 t
->type
.in
= s
->type
.sin
.sin_addr
;
347 memcpy(&t
->type
.in6
, &s
->type
.sin6
.sin6_addr
, 16);
348 #ifdef ISC_PLATFORM_HAVESCOPEID
349 t
->zone
= s
->type
.sin6
.sin6_scope_id
;
354 #ifdef ISC_PLATFORM_HAVESYSUNH
356 memcpy(t
->type
.un
, s
->type
.sunix
.sun_path
, sizeof(t
->type
.un
));
366 isc_netaddr_any(isc_netaddr_t
*netaddr
) {
367 memset(netaddr
, 0, sizeof(*netaddr
));
368 netaddr
->family
= AF_INET
;
369 netaddr
->type
.in
.s_addr
= INADDR_ANY
;
373 isc_netaddr_any6(isc_netaddr_t
*netaddr
) {
374 memset(netaddr
, 0, sizeof(*netaddr
));
375 netaddr
->family
= AF_INET6
;
376 netaddr
->type
.in6
= in6addr_any
;
380 isc_netaddr_ismulticast(isc_netaddr_t
*na
) {
381 switch (na
->family
) {
383 return (ISC_TF(ISC_IPADDR_ISMULTICAST(na
->type
.in
.s_addr
)));
385 return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na
->type
.in6
)));
387 return (ISC_FALSE
); /* XXXMLG ? */
392 isc_netaddr_isexperimental(isc_netaddr_t
*na
) {
393 switch (na
->family
) {
395 return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na
->type
.in
.s_addr
)));
397 return (ISC_FALSE
); /* XXXMLG ? */
402 isc_netaddr_islinklocal(isc_netaddr_t
*na
) {
403 switch (na
->family
) {
407 return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na
->type
.in6
)));
414 isc_netaddr_issitelocal(isc_netaddr_t
*na
) {
415 switch (na
->family
) {
419 return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na
->type
.in6
)));
426 isc_netaddr_fromv4mapped(isc_netaddr_t
*t
, const isc_netaddr_t
*s
) {
429 DE_CONST(s
, src
); /* Must come before IN6_IS_ADDR_V4MAPPED. */
431 REQUIRE(s
->family
== AF_INET6
);
432 REQUIRE(IN6_IS_ADDR_V4MAPPED(&src
->type
.in6
));
434 memset(t
, 0, sizeof(*t
));
436 memcpy(&t
->type
.in
, (char *)&src
->type
.in6
+ 12, 4);