1*ba1276acSMatthew Dillon /* $OpenBSD: addr.c,v 1.8 2024/04/02 09:29:31 deraadt Exp $ */
250a69bb5SSascha Wildner
350a69bb5SSascha Wildner /*
450a69bb5SSascha Wildner * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
550a69bb5SSascha Wildner *
650a69bb5SSascha Wildner * Permission to use, copy, modify, and distribute this software for any
750a69bb5SSascha Wildner * purpose with or without fee is hereby granted, provided that the above
850a69bb5SSascha Wildner * copyright notice and this permission notice appear in all copies.
950a69bb5SSascha Wildner *
1050a69bb5SSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1150a69bb5SSascha Wildner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1250a69bb5SSascha Wildner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1350a69bb5SSascha Wildner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1450a69bb5SSascha Wildner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1550a69bb5SSascha Wildner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1650a69bb5SSascha Wildner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1750a69bb5SSascha Wildner */
1850a69bb5SSascha Wildner
1950a69bb5SSascha Wildner #include "includes.h"
2050a69bb5SSascha Wildner
2150a69bb5SSascha Wildner #include <sys/types.h>
2250a69bb5SSascha Wildner #include <sys/socket.h>
2350a69bb5SSascha Wildner #include <netinet/in.h>
2450a69bb5SSascha Wildner #include <arpa/inet.h>
2550a69bb5SSascha Wildner
2650a69bb5SSascha Wildner #include <netdb.h>
2750a69bb5SSascha Wildner #include <string.h>
2850a69bb5SSascha Wildner #include <stdlib.h>
2950a69bb5SSascha Wildner #include <stdio.h>
30*ba1276acSMatthew Dillon #include <limits.h>
3150a69bb5SSascha Wildner
3250a69bb5SSascha Wildner #include "addr.h"
3350a69bb5SSascha Wildner
3450a69bb5SSascha Wildner #define _SA(x) ((struct sockaddr *)(x))
3550a69bb5SSascha Wildner
3650a69bb5SSascha Wildner int
addr_unicast_masklen(int af)3750a69bb5SSascha Wildner addr_unicast_masklen(int af)
3850a69bb5SSascha Wildner {
3950a69bb5SSascha Wildner switch (af) {
4050a69bb5SSascha Wildner case AF_INET:
4150a69bb5SSascha Wildner return 32;
4250a69bb5SSascha Wildner case AF_INET6:
4350a69bb5SSascha Wildner return 128;
4450a69bb5SSascha Wildner default:
4550a69bb5SSascha Wildner return -1;
4650a69bb5SSascha Wildner }
4750a69bb5SSascha Wildner }
4850a69bb5SSascha Wildner
4950a69bb5SSascha Wildner static inline int
masklen_valid(int af,u_int masklen)5050a69bb5SSascha Wildner masklen_valid(int af, u_int masklen)
5150a69bb5SSascha Wildner {
5250a69bb5SSascha Wildner switch (af) {
5350a69bb5SSascha Wildner case AF_INET:
5450a69bb5SSascha Wildner return masklen <= 32 ? 0 : -1;
5550a69bb5SSascha Wildner case AF_INET6:
5650a69bb5SSascha Wildner return masklen <= 128 ? 0 : -1;
5750a69bb5SSascha Wildner default:
5850a69bb5SSascha Wildner return -1;
5950a69bb5SSascha Wildner }
6050a69bb5SSascha Wildner }
6150a69bb5SSascha Wildner
6250a69bb5SSascha Wildner int
addr_xaddr_to_sa(const struct xaddr * xa,struct sockaddr * sa,socklen_t * len,u_int16_t port)6350a69bb5SSascha Wildner addr_xaddr_to_sa(const struct xaddr *xa, struct sockaddr *sa, socklen_t *len,
6450a69bb5SSascha Wildner u_int16_t port)
6550a69bb5SSascha Wildner {
6650a69bb5SSascha Wildner struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
6750a69bb5SSascha Wildner struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
6850a69bb5SSascha Wildner
6950a69bb5SSascha Wildner if (xa == NULL || sa == NULL || len == NULL)
7050a69bb5SSascha Wildner return -1;
7150a69bb5SSascha Wildner
7250a69bb5SSascha Wildner switch (xa->af) {
7350a69bb5SSascha Wildner case AF_INET:
7450a69bb5SSascha Wildner if (*len < sizeof(*in4))
7550a69bb5SSascha Wildner return -1;
7650a69bb5SSascha Wildner memset(sa, '\0', sizeof(*in4));
7750a69bb5SSascha Wildner *len = sizeof(*in4);
7850a69bb5SSascha Wildner #ifdef SOCK_HAS_LEN
7950a69bb5SSascha Wildner in4->sin_len = sizeof(*in4);
8050a69bb5SSascha Wildner #endif
8150a69bb5SSascha Wildner in4->sin_family = AF_INET;
8250a69bb5SSascha Wildner in4->sin_port = htons(port);
8350a69bb5SSascha Wildner memcpy(&in4->sin_addr, &xa->v4, sizeof(in4->sin_addr));
8450a69bb5SSascha Wildner break;
8550a69bb5SSascha Wildner case AF_INET6:
8650a69bb5SSascha Wildner if (*len < sizeof(*in6))
8750a69bb5SSascha Wildner return -1;
8850a69bb5SSascha Wildner memset(sa, '\0', sizeof(*in6));
8950a69bb5SSascha Wildner *len = sizeof(*in6);
9050a69bb5SSascha Wildner #ifdef SOCK_HAS_LEN
9150a69bb5SSascha Wildner in6->sin6_len = sizeof(*in6);
9250a69bb5SSascha Wildner #endif
9350a69bb5SSascha Wildner in6->sin6_family = AF_INET6;
9450a69bb5SSascha Wildner in6->sin6_port = htons(port);
9550a69bb5SSascha Wildner memcpy(&in6->sin6_addr, &xa->v6, sizeof(in6->sin6_addr));
9650a69bb5SSascha Wildner #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
9750a69bb5SSascha Wildner in6->sin6_scope_id = xa->scope_id;
9850a69bb5SSascha Wildner #endif
9950a69bb5SSascha Wildner break;
10050a69bb5SSascha Wildner default:
10150a69bb5SSascha Wildner return -1;
10250a69bb5SSascha Wildner }
10350a69bb5SSascha Wildner return 0;
10450a69bb5SSascha Wildner }
10550a69bb5SSascha Wildner
10650a69bb5SSascha Wildner /*
10750a69bb5SSascha Wildner * Convert struct sockaddr to struct xaddr
10850a69bb5SSascha Wildner * Returns 0 on success, -1 on failure.
10950a69bb5SSascha Wildner */
11050a69bb5SSascha Wildner int
addr_sa_to_xaddr(struct sockaddr * sa,socklen_t slen,struct xaddr * xa)11150a69bb5SSascha Wildner addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
11250a69bb5SSascha Wildner {
11350a69bb5SSascha Wildner struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
11450a69bb5SSascha Wildner struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
11550a69bb5SSascha Wildner
11650a69bb5SSascha Wildner memset(xa, '\0', sizeof(*xa));
11750a69bb5SSascha Wildner
11850a69bb5SSascha Wildner switch (sa->sa_family) {
11950a69bb5SSascha Wildner case AF_INET:
12050a69bb5SSascha Wildner if (slen < (socklen_t)sizeof(*in4))
12150a69bb5SSascha Wildner return -1;
12250a69bb5SSascha Wildner xa->af = AF_INET;
12350a69bb5SSascha Wildner memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
12450a69bb5SSascha Wildner break;
12550a69bb5SSascha Wildner case AF_INET6:
12650a69bb5SSascha Wildner if (slen < (socklen_t)sizeof(*in6))
12750a69bb5SSascha Wildner return -1;
12850a69bb5SSascha Wildner xa->af = AF_INET6;
12950a69bb5SSascha Wildner memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
13050a69bb5SSascha Wildner #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
13150a69bb5SSascha Wildner xa->scope_id = in6->sin6_scope_id;
13250a69bb5SSascha Wildner #endif
13350a69bb5SSascha Wildner break;
13450a69bb5SSascha Wildner default:
13550a69bb5SSascha Wildner return -1;
13650a69bb5SSascha Wildner }
13750a69bb5SSascha Wildner
13850a69bb5SSascha Wildner return 0;
13950a69bb5SSascha Wildner }
14050a69bb5SSascha Wildner
14150a69bb5SSascha Wildner int
addr_invert(struct xaddr * n)14250a69bb5SSascha Wildner addr_invert(struct xaddr *n)
14350a69bb5SSascha Wildner {
14450a69bb5SSascha Wildner int i;
14550a69bb5SSascha Wildner
14650a69bb5SSascha Wildner if (n == NULL)
14750a69bb5SSascha Wildner return -1;
14850a69bb5SSascha Wildner
14950a69bb5SSascha Wildner switch (n->af) {
15050a69bb5SSascha Wildner case AF_INET:
15150a69bb5SSascha Wildner n->v4.s_addr = ~n->v4.s_addr;
15250a69bb5SSascha Wildner return 0;
15350a69bb5SSascha Wildner case AF_INET6:
15450a69bb5SSascha Wildner for (i = 0; i < 4; i++)
15550a69bb5SSascha Wildner n->addr32[i] = ~n->addr32[i];
15650a69bb5SSascha Wildner return 0;
15750a69bb5SSascha Wildner default:
15850a69bb5SSascha Wildner return -1;
15950a69bb5SSascha Wildner }
16050a69bb5SSascha Wildner }
16150a69bb5SSascha Wildner
16250a69bb5SSascha Wildner /*
16350a69bb5SSascha Wildner * Calculate a netmask of length 'l' for address family 'af' and
16450a69bb5SSascha Wildner * store it in 'n'.
16550a69bb5SSascha Wildner * Returns 0 on success, -1 on failure.
16650a69bb5SSascha Wildner */
16750a69bb5SSascha Wildner int
addr_netmask(int af,u_int l,struct xaddr * n)16850a69bb5SSascha Wildner addr_netmask(int af, u_int l, struct xaddr *n)
16950a69bb5SSascha Wildner {
17050a69bb5SSascha Wildner int i;
17150a69bb5SSascha Wildner
17250a69bb5SSascha Wildner if (masklen_valid(af, l) != 0 || n == NULL)
17350a69bb5SSascha Wildner return -1;
17450a69bb5SSascha Wildner
17550a69bb5SSascha Wildner memset(n, '\0', sizeof(*n));
17650a69bb5SSascha Wildner switch (af) {
17750a69bb5SSascha Wildner case AF_INET:
17850a69bb5SSascha Wildner n->af = AF_INET;
17950a69bb5SSascha Wildner if (l == 0)
18050a69bb5SSascha Wildner return 0;
18150a69bb5SSascha Wildner n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
18250a69bb5SSascha Wildner return 0;
18350a69bb5SSascha Wildner case AF_INET6:
18450a69bb5SSascha Wildner n->af = AF_INET6;
18550a69bb5SSascha Wildner for (i = 0; i < 4 && l >= 32; i++, l -= 32)
18650a69bb5SSascha Wildner n->addr32[i] = 0xffffffffU;
18750a69bb5SSascha Wildner if (i < 4 && l != 0)
18850a69bb5SSascha Wildner n->addr32[i] = htonl((0xffffffff << (32 - l)) &
18950a69bb5SSascha Wildner 0xffffffff);
19050a69bb5SSascha Wildner return 0;
19150a69bb5SSascha Wildner default:
19250a69bb5SSascha Wildner return -1;
19350a69bb5SSascha Wildner }
19450a69bb5SSascha Wildner }
19550a69bb5SSascha Wildner
19650a69bb5SSascha Wildner int
addr_hostmask(int af,u_int l,struct xaddr * n)19750a69bb5SSascha Wildner addr_hostmask(int af, u_int l, struct xaddr *n)
19850a69bb5SSascha Wildner {
19950a69bb5SSascha Wildner if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
20050a69bb5SSascha Wildner return -1;
20150a69bb5SSascha Wildner return 0;
20250a69bb5SSascha Wildner }
20350a69bb5SSascha Wildner
20450a69bb5SSascha Wildner /*
20550a69bb5SSascha Wildner * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
20650a69bb5SSascha Wildner * Returns 0 on success, -1 on failure.
20750a69bb5SSascha Wildner */
20850a69bb5SSascha Wildner int
addr_and(struct xaddr * dst,const struct xaddr * a,const struct xaddr * b)20950a69bb5SSascha Wildner addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
21050a69bb5SSascha Wildner {
21150a69bb5SSascha Wildner int i;
21250a69bb5SSascha Wildner
21350a69bb5SSascha Wildner if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
21450a69bb5SSascha Wildner return -1;
21550a69bb5SSascha Wildner
21650a69bb5SSascha Wildner memcpy(dst, a, sizeof(*dst));
21750a69bb5SSascha Wildner switch (a->af) {
21850a69bb5SSascha Wildner case AF_INET:
21950a69bb5SSascha Wildner dst->v4.s_addr &= b->v4.s_addr;
22050a69bb5SSascha Wildner return 0;
22150a69bb5SSascha Wildner case AF_INET6:
22250a69bb5SSascha Wildner dst->scope_id = a->scope_id;
22350a69bb5SSascha Wildner for (i = 0; i < 4; i++)
22450a69bb5SSascha Wildner dst->addr32[i] &= b->addr32[i];
22550a69bb5SSascha Wildner return 0;
22650a69bb5SSascha Wildner default:
22750a69bb5SSascha Wildner return -1;
22850a69bb5SSascha Wildner }
22950a69bb5SSascha Wildner }
23050a69bb5SSascha Wildner
23150a69bb5SSascha Wildner int
addr_or(struct xaddr * dst,const struct xaddr * a,const struct xaddr * b)232*ba1276acSMatthew Dillon addr_or(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
233*ba1276acSMatthew Dillon {
234*ba1276acSMatthew Dillon int i;
235*ba1276acSMatthew Dillon
236*ba1276acSMatthew Dillon if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
237*ba1276acSMatthew Dillon return (-1);
238*ba1276acSMatthew Dillon
239*ba1276acSMatthew Dillon memcpy(dst, a, sizeof(*dst));
240*ba1276acSMatthew Dillon switch (a->af) {
241*ba1276acSMatthew Dillon case AF_INET:
242*ba1276acSMatthew Dillon dst->v4.s_addr |= b->v4.s_addr;
243*ba1276acSMatthew Dillon return (0);
244*ba1276acSMatthew Dillon case AF_INET6:
245*ba1276acSMatthew Dillon for (i = 0; i < 4; i++)
246*ba1276acSMatthew Dillon dst->addr32[i] |= b->addr32[i];
247*ba1276acSMatthew Dillon return (0);
248*ba1276acSMatthew Dillon default:
249*ba1276acSMatthew Dillon return (-1);
250*ba1276acSMatthew Dillon }
251*ba1276acSMatthew Dillon }
252*ba1276acSMatthew Dillon
253*ba1276acSMatthew Dillon int
addr_cmp(const struct xaddr * a,const struct xaddr * b)25450a69bb5SSascha Wildner addr_cmp(const struct xaddr *a, const struct xaddr *b)
25550a69bb5SSascha Wildner {
25650a69bb5SSascha Wildner int i;
25750a69bb5SSascha Wildner
25850a69bb5SSascha Wildner if (a->af != b->af)
25950a69bb5SSascha Wildner return (a->af == AF_INET6 ? 1 : -1);
26050a69bb5SSascha Wildner
26150a69bb5SSascha Wildner switch (a->af) {
26250a69bb5SSascha Wildner case AF_INET:
26350a69bb5SSascha Wildner /*
26450a69bb5SSascha Wildner * Can't just subtract here as 255.255.255.255 - 0.0.0.0 is
26550a69bb5SSascha Wildner * too big to fit into a signed int
26650a69bb5SSascha Wildner */
26750a69bb5SSascha Wildner if (a->v4.s_addr == b->v4.s_addr)
26850a69bb5SSascha Wildner return 0;
26950a69bb5SSascha Wildner return (ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1);
270ee116499SAntonio Huete Jimenez case AF_INET6:
27150a69bb5SSascha Wildner /*
27250a69bb5SSascha Wildner * Do this a byte at a time to avoid the above issue and
27350a69bb5SSascha Wildner * any endian problems
27450a69bb5SSascha Wildner */
27550a69bb5SSascha Wildner for (i = 0; i < 16; i++)
27650a69bb5SSascha Wildner if (a->addr8[i] - b->addr8[i] != 0)
27750a69bb5SSascha Wildner return (a->addr8[i] - b->addr8[i]);
27850a69bb5SSascha Wildner if (a->scope_id == b->scope_id)
27950a69bb5SSascha Wildner return (0);
28050a69bb5SSascha Wildner return (a->scope_id > b->scope_id ? 1 : -1);
28150a69bb5SSascha Wildner default:
28250a69bb5SSascha Wildner return (-1);
28350a69bb5SSascha Wildner }
28450a69bb5SSascha Wildner }
28550a69bb5SSascha Wildner
28650a69bb5SSascha Wildner int
addr_is_all0s(const struct xaddr * a)28750a69bb5SSascha Wildner addr_is_all0s(const struct xaddr *a)
28850a69bb5SSascha Wildner {
28950a69bb5SSascha Wildner int i;
29050a69bb5SSascha Wildner
29150a69bb5SSascha Wildner switch (a->af) {
29250a69bb5SSascha Wildner case AF_INET:
29350a69bb5SSascha Wildner return (a->v4.s_addr == 0 ? 0 : -1);
294ee116499SAntonio Huete Jimenez case AF_INET6:
29550a69bb5SSascha Wildner for (i = 0; i < 4; i++)
29650a69bb5SSascha Wildner if (a->addr32[i] != 0)
29750a69bb5SSascha Wildner return -1;
29850a69bb5SSascha Wildner return 0;
29950a69bb5SSascha Wildner default:
30050a69bb5SSascha Wildner return -1;
30150a69bb5SSascha Wildner }
30250a69bb5SSascha Wildner }
30350a69bb5SSascha Wildner
304*ba1276acSMatthew Dillon /* Increment the specified address. Note, does not do overflow checking */
305*ba1276acSMatthew Dillon void
addr_increment(struct xaddr * a)306*ba1276acSMatthew Dillon addr_increment(struct xaddr *a)
307*ba1276acSMatthew Dillon {
308*ba1276acSMatthew Dillon int i;
309*ba1276acSMatthew Dillon uint32_t n;
310*ba1276acSMatthew Dillon
311*ba1276acSMatthew Dillon switch (a->af) {
312*ba1276acSMatthew Dillon case AF_INET:
313*ba1276acSMatthew Dillon a->v4.s_addr = htonl(ntohl(a->v4.s_addr) + 1);
314*ba1276acSMatthew Dillon break;
315*ba1276acSMatthew Dillon case AF_INET6:
316*ba1276acSMatthew Dillon for (i = 0; i < 4; i++) {
317*ba1276acSMatthew Dillon /* Increment with carry */
318*ba1276acSMatthew Dillon n = ntohl(a->addr32[3 - i]) + 1;
319*ba1276acSMatthew Dillon a->addr32[3 - i] = htonl(n);
320*ba1276acSMatthew Dillon if (n != 0)
321*ba1276acSMatthew Dillon break;
322*ba1276acSMatthew Dillon }
323*ba1276acSMatthew Dillon break;
324*ba1276acSMatthew Dillon }
325*ba1276acSMatthew Dillon }
326*ba1276acSMatthew Dillon
32750a69bb5SSascha Wildner /*
32850a69bb5SSascha Wildner * Test whether host portion of address 'a', as determined by 'masklen'
32950a69bb5SSascha Wildner * is all zeros.
330ee116499SAntonio Huete Jimenez * Returns 0 if host portion of address is all-zeros,
33150a69bb5SSascha Wildner * -1 if not all zeros or on failure.
33250a69bb5SSascha Wildner */
33350a69bb5SSascha Wildner int
addr_host_is_all0s(const struct xaddr * a,u_int masklen)33450a69bb5SSascha Wildner addr_host_is_all0s(const struct xaddr *a, u_int masklen)
33550a69bb5SSascha Wildner {
33650a69bb5SSascha Wildner struct xaddr tmp_addr, tmp_mask, tmp_result;
33750a69bb5SSascha Wildner
33850a69bb5SSascha Wildner memcpy(&tmp_addr, a, sizeof(tmp_addr));
33950a69bb5SSascha Wildner if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
34050a69bb5SSascha Wildner return -1;
34150a69bb5SSascha Wildner if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
34250a69bb5SSascha Wildner return -1;
34350a69bb5SSascha Wildner return addr_is_all0s(&tmp_result);
34450a69bb5SSascha Wildner }
34550a69bb5SSascha Wildner
346*ba1276acSMatthew Dillon #if 0
347*ba1276acSMatthew Dillon int
348*ba1276acSMatthew Dillon addr_host_to_all0s(struct xaddr *a, u_int masklen)
349*ba1276acSMatthew Dillon {
350*ba1276acSMatthew Dillon struct xaddr tmp_mask;
351*ba1276acSMatthew Dillon
352*ba1276acSMatthew Dillon if (addr_netmask(a->af, masklen, &tmp_mask) == -1)
353*ba1276acSMatthew Dillon return (-1);
354*ba1276acSMatthew Dillon if (addr_and(a, a, &tmp_mask) == -1)
355*ba1276acSMatthew Dillon return (-1);
356*ba1276acSMatthew Dillon return (0);
357*ba1276acSMatthew Dillon }
358*ba1276acSMatthew Dillon #endif
359*ba1276acSMatthew Dillon
360*ba1276acSMatthew Dillon int
addr_host_to_all1s(struct xaddr * a,u_int masklen)361*ba1276acSMatthew Dillon addr_host_to_all1s(struct xaddr *a, u_int masklen)
362*ba1276acSMatthew Dillon {
363*ba1276acSMatthew Dillon struct xaddr tmp_mask;
364*ba1276acSMatthew Dillon
365*ba1276acSMatthew Dillon if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
366*ba1276acSMatthew Dillon return (-1);
367*ba1276acSMatthew Dillon if (addr_or(a, a, &tmp_mask) == -1)
368*ba1276acSMatthew Dillon return (-1);
369*ba1276acSMatthew Dillon return (0);
370*ba1276acSMatthew Dillon }
371*ba1276acSMatthew Dillon
37250a69bb5SSascha Wildner /*
373ee116499SAntonio Huete Jimenez * Parse string address 'p' into 'n'.
37450a69bb5SSascha Wildner * Returns 0 on success, -1 on failure.
37550a69bb5SSascha Wildner */
37650a69bb5SSascha Wildner int
addr_pton(const char * p,struct xaddr * n)37750a69bb5SSascha Wildner addr_pton(const char *p, struct xaddr *n)
37850a69bb5SSascha Wildner {
37950a69bb5SSascha Wildner struct addrinfo hints, *ai;
38050a69bb5SSascha Wildner
38150a69bb5SSascha Wildner memset(&hints, '\0', sizeof(hints));
38250a69bb5SSascha Wildner hints.ai_flags = AI_NUMERICHOST;
38350a69bb5SSascha Wildner
38450a69bb5SSascha Wildner if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
38550a69bb5SSascha Wildner return -1;
38650a69bb5SSascha Wildner
387ee116499SAntonio Huete Jimenez if (ai == NULL)
38850a69bb5SSascha Wildner return -1;
38950a69bb5SSascha Wildner
390ee116499SAntonio Huete Jimenez if (ai->ai_addr == NULL) {
391ee116499SAntonio Huete Jimenez freeaddrinfo(ai);
392ee116499SAntonio Huete Jimenez return -1;
393ee116499SAntonio Huete Jimenez }
394ee116499SAntonio Huete Jimenez
39550a69bb5SSascha Wildner if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen,
39650a69bb5SSascha Wildner n) == -1) {
39750a69bb5SSascha Wildner freeaddrinfo(ai);
39850a69bb5SSascha Wildner return -1;
39950a69bb5SSascha Wildner }
40050a69bb5SSascha Wildner
40150a69bb5SSascha Wildner freeaddrinfo(ai);
40250a69bb5SSascha Wildner return 0;
40350a69bb5SSascha Wildner }
40450a69bb5SSascha Wildner
40550a69bb5SSascha Wildner int
addr_sa_pton(const char * h,const char * s,struct sockaddr * sa,socklen_t slen)40650a69bb5SSascha Wildner addr_sa_pton(const char *h, const char *s, struct sockaddr *sa, socklen_t slen)
40750a69bb5SSascha Wildner {
40850a69bb5SSascha Wildner struct addrinfo hints, *ai;
40950a69bb5SSascha Wildner
41050a69bb5SSascha Wildner memset(&hints, '\0', sizeof(hints));
41150a69bb5SSascha Wildner hints.ai_flags = AI_NUMERICHOST;
41250a69bb5SSascha Wildner
41350a69bb5SSascha Wildner if (h == NULL || getaddrinfo(h, s, &hints, &ai) != 0)
41450a69bb5SSascha Wildner return -1;
41550a69bb5SSascha Wildner
416ee116499SAntonio Huete Jimenez if (ai == NULL)
41750a69bb5SSascha Wildner return -1;
41850a69bb5SSascha Wildner
419ee116499SAntonio Huete Jimenez if (ai->ai_addr == NULL) {
420ee116499SAntonio Huete Jimenez freeaddrinfo(ai);
42150a69bb5SSascha Wildner return -1;
422ee116499SAntonio Huete Jimenez }
423ee116499SAntonio Huete Jimenez
424ee116499SAntonio Huete Jimenez if (sa != NULL) {
425ee116499SAntonio Huete Jimenez if (slen < ai->ai_addrlen) {
426ee116499SAntonio Huete Jimenez freeaddrinfo(ai);
427ee116499SAntonio Huete Jimenez return -1;
428ee116499SAntonio Huete Jimenez }
42950a69bb5SSascha Wildner memcpy(sa, &ai->ai_addr, ai->ai_addrlen);
43050a69bb5SSascha Wildner }
43150a69bb5SSascha Wildner
43250a69bb5SSascha Wildner freeaddrinfo(ai);
43350a69bb5SSascha Wildner return 0;
43450a69bb5SSascha Wildner }
43550a69bb5SSascha Wildner
43650a69bb5SSascha Wildner int
addr_ntop(const struct xaddr * n,char * p,size_t len)43750a69bb5SSascha Wildner addr_ntop(const struct xaddr *n, char *p, size_t len)
43850a69bb5SSascha Wildner {
43950a69bb5SSascha Wildner struct sockaddr_storage ss;
44050a69bb5SSascha Wildner socklen_t slen = sizeof(ss);
44150a69bb5SSascha Wildner
44250a69bb5SSascha Wildner if (addr_xaddr_to_sa(n, _SA(&ss), &slen, 0) == -1)
44350a69bb5SSascha Wildner return -1;
444ee116499SAntonio Huete Jimenez if (p == NULL || len == 0)
44550a69bb5SSascha Wildner return -1;
44650a69bb5SSascha Wildner if (getnameinfo(_SA(&ss), slen, p, len, NULL, 0,
447*ba1276acSMatthew Dillon NI_NUMERICHOST) != 0)
44850a69bb5SSascha Wildner return -1;
44950a69bb5SSascha Wildner
45050a69bb5SSascha Wildner return 0;
45150a69bb5SSascha Wildner }
45250a69bb5SSascha Wildner
45350a69bb5SSascha Wildner /*
45450a69bb5SSascha Wildner * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
45550a69bb5SSascha Wildner * Return -1 on parse error, -2 on inconsistency or 0 on success.
45650a69bb5SSascha Wildner */
45750a69bb5SSascha Wildner int
addr_pton_cidr(const char * p,struct xaddr * n,u_int * l)45850a69bb5SSascha Wildner addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
45950a69bb5SSascha Wildner {
46050a69bb5SSascha Wildner struct xaddr tmp;
461*ba1276acSMatthew Dillon u_int masklen = 999;
462*ba1276acSMatthew Dillon char addrbuf[64], *mp;
463*ba1276acSMatthew Dillon const char *errstr;
46450a69bb5SSascha Wildner
46550a69bb5SSascha Wildner /* Don't modify argument */
46650a69bb5SSascha Wildner if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) >= sizeof(addrbuf))
46750a69bb5SSascha Wildner return -1;
46850a69bb5SSascha Wildner
46950a69bb5SSascha Wildner if ((mp = strchr(addrbuf, '/')) != NULL) {
47050a69bb5SSascha Wildner *mp = '\0';
47150a69bb5SSascha Wildner mp++;
472*ba1276acSMatthew Dillon masklen = (u_int)strtonum(mp, 0, INT_MAX, &errstr);
473*ba1276acSMatthew Dillon if (errstr)
47450a69bb5SSascha Wildner return -1;
47550a69bb5SSascha Wildner }
47650a69bb5SSascha Wildner
47750a69bb5SSascha Wildner if (addr_pton(addrbuf, &tmp) == -1)
47850a69bb5SSascha Wildner return -1;
47950a69bb5SSascha Wildner
48050a69bb5SSascha Wildner if (mp == NULL)
48150a69bb5SSascha Wildner masklen = addr_unicast_masklen(tmp.af);
48250a69bb5SSascha Wildner if (masklen_valid(tmp.af, masklen) == -1)
48350a69bb5SSascha Wildner return -2;
48450a69bb5SSascha Wildner if (addr_host_is_all0s(&tmp, masklen) != 0)
48550a69bb5SSascha Wildner return -2;
48650a69bb5SSascha Wildner
48750a69bb5SSascha Wildner if (n != NULL)
48850a69bb5SSascha Wildner memcpy(n, &tmp, sizeof(*n));
48950a69bb5SSascha Wildner if (l != NULL)
49050a69bb5SSascha Wildner *l = masklen;
49150a69bb5SSascha Wildner
49250a69bb5SSascha Wildner return 0;
49350a69bb5SSascha Wildner }
49450a69bb5SSascha Wildner
49550a69bb5SSascha Wildner int
addr_netmatch(const struct xaddr * host,const struct xaddr * net,u_int masklen)49650a69bb5SSascha Wildner addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
49750a69bb5SSascha Wildner {
49850a69bb5SSascha Wildner struct xaddr tmp_mask, tmp_result;
49950a69bb5SSascha Wildner
50050a69bb5SSascha Wildner if (host->af != net->af)
50150a69bb5SSascha Wildner return -1;
50250a69bb5SSascha Wildner
50350a69bb5SSascha Wildner if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
50450a69bb5SSascha Wildner return -1;
50550a69bb5SSascha Wildner if (addr_and(&tmp_result, host, &tmp_mask) == -1)
50650a69bb5SSascha Wildner return -1;
50750a69bb5SSascha Wildner return addr_cmp(&tmp_result, net);
50850a69bb5SSascha Wildner }
509