1 /* $OpenBSD: addr.c,v 1.5 2022/04/29 04:55:07 djm Exp $ */
4 * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
33 #define _SA(x) ((struct sockaddr *)(x))
36 addr_unicast_masklen(int af
)
49 masklen_valid(int af
, u_int masklen
)
53 return masklen
<= 32 ? 0 : -1;
55 return masklen
<= 128 ? 0 : -1;
62 addr_xaddr_to_sa(const struct xaddr
*xa
, struct sockaddr
*sa
, socklen_t
*len
,
65 struct sockaddr_in
*in4
= (struct sockaddr_in
*)sa
;
66 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)sa
;
68 if (xa
== NULL
|| sa
== NULL
|| len
== NULL
)
73 if (*len
< sizeof(*in4
))
75 memset(sa
, '\0', sizeof(*in4
));
78 in4
->sin_len
= sizeof(*in4
);
80 in4
->sin_family
= AF_INET
;
81 in4
->sin_port
= htons(port
);
82 memcpy(&in4
->sin_addr
, &xa
->v4
, sizeof(in4
->sin_addr
));
85 if (*len
< sizeof(*in6
))
87 memset(sa
, '\0', sizeof(*in6
));
90 in6
->sin6_len
= sizeof(*in6
);
92 in6
->sin6_family
= AF_INET6
;
93 in6
->sin6_port
= htons(port
);
94 memcpy(&in6
->sin6_addr
, &xa
->v6
, sizeof(in6
->sin6_addr
));
95 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
96 in6
->sin6_scope_id
= xa
->scope_id
;
106 * Convert struct sockaddr to struct xaddr
107 * Returns 0 on success, -1 on failure.
110 addr_sa_to_xaddr(struct sockaddr
*sa
, socklen_t slen
, struct xaddr
*xa
)
112 struct sockaddr_in
*in4
= (struct sockaddr_in
*)sa
;
113 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)sa
;
115 memset(xa
, '\0', sizeof(*xa
));
117 switch (sa
->sa_family
) {
119 if (slen
< (socklen_t
)sizeof(*in4
))
122 memcpy(&xa
->v4
, &in4
->sin_addr
, sizeof(xa
->v4
));
125 if (slen
< (socklen_t
)sizeof(*in6
))
128 memcpy(&xa
->v6
, &in6
->sin6_addr
, sizeof(xa
->v6
));
129 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
130 xa
->scope_id
= in6
->sin6_scope_id
;
141 addr_invert(struct xaddr
*n
)
150 n
->v4
.s_addr
= ~n
->v4
.s_addr
;
153 for (i
= 0; i
< 4; i
++)
154 n
->addr32
[i
] = ~n
->addr32
[i
];
162 * Calculate a netmask of length 'l' for address family 'af' and
164 * Returns 0 on success, -1 on failure.
167 addr_netmask(int af
, u_int l
, struct xaddr
*n
)
171 if (masklen_valid(af
, l
) != 0 || n
== NULL
)
174 memset(n
, '\0', sizeof(*n
));
180 n
->v4
.s_addr
= htonl((0xffffffff << (32 - l
)) & 0xffffffff);
184 for (i
= 0; i
< 4 && l
>= 32; i
++, l
-= 32)
185 n
->addr32
[i
] = 0xffffffffU
;
187 n
->addr32
[i
] = htonl((0xffffffff << (32 - l
)) &
196 addr_hostmask(int af
, u_int l
, struct xaddr
*n
)
198 if (addr_netmask(af
, l
, n
) == -1 || addr_invert(n
) == -1)
204 * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
205 * Returns 0 on success, -1 on failure.
208 addr_and(struct xaddr
*dst
, const struct xaddr
*a
, const struct xaddr
*b
)
212 if (dst
== NULL
|| a
== NULL
|| b
== NULL
|| a
->af
!= b
->af
)
215 memcpy(dst
, a
, sizeof(*dst
));
218 dst
->v4
.s_addr
&= b
->v4
.s_addr
;
221 dst
->scope_id
= a
->scope_id
;
222 for (i
= 0; i
< 4; i
++)
223 dst
->addr32
[i
] &= b
->addr32
[i
];
231 addr_cmp(const struct xaddr
*a
, const struct xaddr
*b
)
236 return (a
->af
== AF_INET6
? 1 : -1);
241 * Can't just subtract here as 255.255.255.255 - 0.0.0.0 is
242 * too big to fit into a signed int
244 if (a
->v4
.s_addr
== b
->v4
.s_addr
)
246 return (ntohl(a
->v4
.s_addr
) > ntohl(b
->v4
.s_addr
) ? 1 : -1);
249 * Do this a byte at a time to avoid the above issue and
250 * any endian problems
252 for (i
= 0; i
< 16; i
++)
253 if (a
->addr8
[i
] - b
->addr8
[i
] != 0)
254 return (a
->addr8
[i
] - b
->addr8
[i
]);
255 if (a
->scope_id
== b
->scope_id
)
257 return (a
->scope_id
> b
->scope_id
? 1 : -1);
264 addr_is_all0s(const struct xaddr
*a
)
270 return (a
->v4
.s_addr
== 0 ? 0 : -1);
272 for (i
= 0; i
< 4; i
++)
273 if (a
->addr32
[i
] != 0)
282 * Test whether host portion of address 'a', as determined by 'masklen'
284 * Returns 0 if host portion of address is all-zeros,
285 * -1 if not all zeros or on failure.
288 addr_host_is_all0s(const struct xaddr
*a
, u_int masklen
)
290 struct xaddr tmp_addr
, tmp_mask
, tmp_result
;
292 memcpy(&tmp_addr
, a
, sizeof(tmp_addr
));
293 if (addr_hostmask(a
->af
, masklen
, &tmp_mask
) == -1)
295 if (addr_and(&tmp_result
, &tmp_addr
, &tmp_mask
) == -1)
297 return addr_is_all0s(&tmp_result
);
301 * Parse string address 'p' into 'n'.
302 * Returns 0 on success, -1 on failure.
305 addr_pton(const char *p
, struct xaddr
*n
)
307 struct addrinfo hints
, *ai
;
309 memset(&hints
, '\0', sizeof(hints
));
310 hints
.ai_flags
= AI_NUMERICHOST
;
312 if (p
== NULL
|| getaddrinfo(p
, NULL
, &hints
, &ai
) != 0)
318 if (ai
->ai_addr
== NULL
) {
323 if (n
!= NULL
&& addr_sa_to_xaddr(ai
->ai_addr
, ai
->ai_addrlen
,
334 addr_sa_pton(const char *h
, const char *s
, struct sockaddr
*sa
, socklen_t slen
)
336 struct addrinfo hints
, *ai
;
338 memset(&hints
, '\0', sizeof(hints
));
339 hints
.ai_flags
= AI_NUMERICHOST
;
341 if (h
== NULL
|| getaddrinfo(h
, s
, &hints
, &ai
) != 0)
347 if (ai
->ai_addr
== NULL
) {
353 if (slen
< ai
->ai_addrlen
) {
357 memcpy(sa
, &ai
->ai_addr
, ai
->ai_addrlen
);
365 addr_ntop(const struct xaddr
*n
, char *p
, size_t len
)
367 struct sockaddr_storage ss
;
368 socklen_t slen
= sizeof(ss
);
370 if (addr_xaddr_to_sa(n
, _SA(&ss
), &slen
, 0) == -1)
372 if (p
== NULL
|| len
== 0)
374 if (getnameinfo(_SA(&ss
), slen
, p
, len
, NULL
, 0,
375 NI_NUMERICHOST
) == -1)
382 * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
383 * Return -1 on parse error, -2 on inconsistency or 0 on success.
386 addr_pton_cidr(const char *p
, struct xaddr
*n
, u_int
*l
)
389 long unsigned int masklen
= 999;
390 char addrbuf
[64], *mp
, *cp
;
392 /* Don't modify argument */
393 if (p
== NULL
|| strlcpy(addrbuf
, p
, sizeof(addrbuf
)) >= sizeof(addrbuf
))
396 if ((mp
= strchr(addrbuf
, '/')) != NULL
) {
399 masklen
= strtoul(mp
, &cp
, 10);
400 if (*mp
< '0' || *mp
> '9' || *cp
!= '\0' || masklen
> 128)
404 if (addr_pton(addrbuf
, &tmp
) == -1)
408 masklen
= addr_unicast_masklen(tmp
.af
);
409 if (masklen_valid(tmp
.af
, masklen
) == -1)
411 if (addr_host_is_all0s(&tmp
, masklen
) != 0)
415 memcpy(n
, &tmp
, sizeof(*n
));
423 addr_netmatch(const struct xaddr
*host
, const struct xaddr
*net
, u_int masklen
)
425 struct xaddr tmp_mask
, tmp_result
;
427 if (host
->af
!= net
->af
)
430 if (addr_netmask(host
->af
, masklen
, &tmp_mask
) == -1)
432 if (addr_and(&tmp_result
, host
, &tmp_mask
) == -1)
434 return addr_cmp(&tmp_result
, net
);