1 /* $NetBSD: netaddr.c,v 1.6 2014/12/10 04:37:59 christos Exp $ */
4 * Copyright (C) 2004, 2005, 2007, 2010-2012, 2014 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.
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
= NULL
, *pb
= NULL
;
75 unsigned int ipabytes
= 0; /* 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
;
103 * Don't crash if we get a pattern like 10.0.0.1/9999999.
105 if (prefixlen
> ipabytes
* 8)
106 prefixlen
= ipabytes
* 8;
108 nbytes
= prefixlen
/ 8;
109 nbits
= prefixlen
% 8;
112 if (memcmp(pa
, pb
, nbytes
) != 0)
116 unsigned int bytea
, byteb
, mask
;
117 INSIST(nbytes
< ipabytes
);
121 mask
= (0xFF << (8-nbits
)) & 0xFF;
122 if ((bytea
& mask
) != (byteb
& mask
))
129 isc_netaddr_totext(const isc_netaddr_t
*netaddr
, isc_buffer_t
*target
) {
130 char abuf
[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
131 char zbuf
[sizeof("%4294967295")];
137 REQUIRE(netaddr
!= NULL
);
139 switch (netaddr
->family
) {
141 type
= &netaddr
->type
.in
;
144 type
= &netaddr
->type
.in6
;
146 #ifdef ISC_PLATFORM_HAVESYSUNH
148 alen
= strlen(netaddr
->type
.un
);
149 if (alen
> isc_buffer_availablelength(target
))
150 return (ISC_R_NOSPACE
);
151 isc_buffer_putmem(target
,
152 (const unsigned char *)(netaddr
->type
.un
),
154 return (ISC_R_SUCCESS
);
157 return (ISC_R_FAILURE
);
159 r
= inet_ntop(netaddr
->family
, type
, abuf
, sizeof(abuf
));
161 return (ISC_R_FAILURE
);
164 INSIST(alen
< sizeof(abuf
));
167 if (netaddr
->family
== AF_INET6
&& netaddr
->zone
!= 0) {
168 zlen
= snprintf(zbuf
, sizeof(zbuf
), "%%%u", netaddr
->zone
);
170 return (ISC_R_FAILURE
);
171 INSIST((unsigned int)zlen
< sizeof(zbuf
));
174 if (alen
+ zlen
> isc_buffer_availablelength(target
))
175 return (ISC_R_NOSPACE
);
177 isc_buffer_putmem(target
, (unsigned char *)abuf
, alen
);
178 isc_buffer_putmem(target
, (unsigned char *)zbuf
, zlen
);
180 return (ISC_R_SUCCESS
);
184 isc_netaddr_format(const isc_netaddr_t
*na
, char *array
, unsigned int size
) {
188 isc_buffer_init(&buf
, array
, size
);
189 result
= isc_netaddr_totext(na
, &buf
);
197 if (result
== ISC_R_SUCCESS
) {
198 if (isc_buffer_availablelength(&buf
) >= 1)
199 isc_buffer_putuint8(&buf
, 0);
201 result
= ISC_R_NOSPACE
;
204 if (result
!= ISC_R_SUCCESS
) {
205 snprintf(array
, size
,
206 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_NETADDR
,
208 "<unknown address, family %u>"),
210 array
[size
- 1] = '\0';
216 isc_netaddr_prefixok(const isc_netaddr_t
*na
, unsigned int prefixlen
) {
217 static const unsigned char zeros
[16];
218 unsigned int nbits
, nbytes
, ipbytes
= 0;
219 const unsigned char *p
;
221 switch (na
->family
) {
223 p
= (const unsigned char *) &na
->type
.in
;
226 return (ISC_R_RANGE
);
229 p
= (const unsigned char *) &na
->type
.in6
;
232 return (ISC_R_RANGE
);
235 return (ISC_R_NOTIMPLEMENTED
);
237 nbytes
= prefixlen
/ 8;
238 nbits
= prefixlen
% 8;
240 INSIST(nbytes
< ipbytes
);
241 if ((p
[nbytes
] & (0xff>>nbits
)) != 0U)
242 return (ISC_R_FAILURE
);
245 if (nbytes
< ipbytes
&& memcmp(p
+ nbytes
, zeros
, ipbytes
- nbytes
) != 0)
246 return (ISC_R_FAILURE
);
247 return (ISC_R_SUCCESS
);
251 isc_netaddr_masktoprefixlen(const isc_netaddr_t
*s
, unsigned int *lenp
) {
252 unsigned int nbits
= 0, nbytes
= 0, ipbytes
= 0, i
;
253 const unsigned char *p
;
257 p
= (const unsigned char *) &s
->type
.in
;
261 p
= (const unsigned char *) &s
->type
.in6
;
265 return (ISC_R_NOTIMPLEMENTED
);
267 for (i
= 0; i
< ipbytes
; i
++) {
273 unsigned int c
= p
[nbytes
];
274 while ((c
& 0x80) != 0 && nbits
< 8) {
278 return (ISC_R_MASKNONCONTIG
);
281 for (; i
< ipbytes
; i
++) {
283 return (ISC_R_MASKNONCONTIG
);
286 *lenp
= nbytes
* 8 + nbits
;
287 return (ISC_R_SUCCESS
);
291 isc_netaddr_fromin(isc_netaddr_t
*netaddr
, const struct in_addr
*ina
) {
292 memset(netaddr
, 0, sizeof(*netaddr
));
293 netaddr
->family
= AF_INET
;
294 netaddr
->type
.in
= *ina
;
298 isc_netaddr_fromin6(isc_netaddr_t
*netaddr
, const struct in6_addr
*ina6
) {
299 memset(netaddr
, 0, sizeof(*netaddr
));
300 netaddr
->family
= AF_INET6
;
301 netaddr
->type
.in6
= *ina6
;
305 isc_netaddr_frompath(isc_netaddr_t
*netaddr
, const char *path
) {
306 #ifdef ISC_PLATFORM_HAVESYSUNH
307 if (strlen(path
) > sizeof(netaddr
->type
.un
) - 1)
308 return (ISC_R_NOSPACE
);
310 memset(netaddr
, 0, sizeof(*netaddr
));
311 netaddr
->family
= AF_UNIX
;
312 strcpy(netaddr
->type
.un
, path
);
314 return (ISC_R_SUCCESS
);
318 return (ISC_R_NOTIMPLEMENTED
);
324 isc_netaddr_setzone(isc_netaddr_t
*netaddr
, isc_uint32_t zone
) {
325 /* we currently only support AF_INET6. */
326 REQUIRE(netaddr
->family
== AF_INET6
);
328 netaddr
->zone
= zone
;
332 isc_netaddr_getzone(const isc_netaddr_t
*netaddr
) {
333 return (netaddr
->zone
);
337 isc_netaddr_fromsockaddr(isc_netaddr_t
*t
, const isc_sockaddr_t
*s
) {
338 int family
= s
->type
.sa
.sa_family
;
342 t
->type
.in
= s
->type
.sin
.sin_addr
;
346 memmove(&t
->type
.in6
, &s
->type
.sin6
.sin6_addr
, 16);
347 #ifdef ISC_PLATFORM_HAVESCOPEID
348 t
->zone
= s
->type
.sin6
.sin6_scope_id
;
353 #ifdef ISC_PLATFORM_HAVESYSUNH
355 memmove(t
->type
.un
, s
->type
.sunix
.sun_path
, sizeof(t
->type
.un
));
365 isc_netaddr_any(isc_netaddr_t
*netaddr
) {
366 memset(netaddr
, 0, sizeof(*netaddr
));
367 netaddr
->family
= AF_INET
;
368 netaddr
->type
.in
.s_addr
= INADDR_ANY
;
372 isc_netaddr_any6(isc_netaddr_t
*netaddr
) {
373 memset(netaddr
, 0, sizeof(*netaddr
));
374 netaddr
->family
= AF_INET6
;
375 netaddr
->type
.in6
= in6addr_any
;
379 isc_netaddr_ismulticast(isc_netaddr_t
*na
) {
380 switch (na
->family
) {
382 return (ISC_TF(ISC_IPADDR_ISMULTICAST(na
->type
.in
.s_addr
)));
384 return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na
->type
.in6
)));
386 return (ISC_FALSE
); /* XXXMLG ? */
391 isc_netaddr_isexperimental(isc_netaddr_t
*na
) {
392 switch (na
->family
) {
394 return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na
->type
.in
.s_addr
)));
396 return (ISC_FALSE
); /* XXXMLG ? */
401 isc_netaddr_islinklocal(isc_netaddr_t
*na
) {
402 switch (na
->family
) {
406 return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na
->type
.in6
)));
413 isc_netaddr_issitelocal(isc_netaddr_t
*na
) {
414 switch (na
->family
) {
418 return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na
->type
.in6
)));
425 isc_netaddr_fromv4mapped(isc_netaddr_t
*t
, const isc_netaddr_t
*s
) {
428 DE_CONST(s
, src
); /* Must come before IN6_IS_ADDR_V4MAPPED. */
430 REQUIRE(s
->family
== AF_INET6
);
431 REQUIRE(IN6_IS_ADDR_V4MAPPED(&src
->type
.in6
));
433 memset(t
, 0, sizeof(*t
));
435 memmove(&t
->type
.in
, (char *)&src
->type
.in6
+ 12, 4);