111044SHuie-Ying.Lee@Sun.COM /* $OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk Exp $ */
211044SHuie-Ying.Lee@Sun.COM
311044SHuie-Ying.Lee@Sun.COM /*
411044SHuie-Ying.Lee@Sun.COM * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
511044SHuie-Ying.Lee@Sun.COM *
611044SHuie-Ying.Lee@Sun.COM * Permission to use, copy, modify, and distribute this software for any
711044SHuie-Ying.Lee@Sun.COM * purpose with or without fee is hereby granted, provided that the above
811044SHuie-Ying.Lee@Sun.COM * copyright notice and this permission notice appear in all copies.
911044SHuie-Ying.Lee@Sun.COM *
1011044SHuie-Ying.Lee@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1111044SHuie-Ying.Lee@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1211044SHuie-Ying.Lee@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1311044SHuie-Ying.Lee@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1411044SHuie-Ying.Lee@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1511044SHuie-Ying.Lee@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1611044SHuie-Ying.Lee@Sun.COM * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1711044SHuie-Ying.Lee@Sun.COM */
1811044SHuie-Ying.Lee@Sun.COM
1911044SHuie-Ying.Lee@Sun.COM #include "includes.h"
2011044SHuie-Ying.Lee@Sun.COM
2111044SHuie-Ying.Lee@Sun.COM #include <sys/types.h>
2211044SHuie-Ying.Lee@Sun.COM #include <sys/socket.h>
2311044SHuie-Ying.Lee@Sun.COM #include <netinet/in.h>
2411044SHuie-Ying.Lee@Sun.COM #include <arpa/inet.h>
2511044SHuie-Ying.Lee@Sun.COM
2611044SHuie-Ying.Lee@Sun.COM #include <netdb.h>
2711044SHuie-Ying.Lee@Sun.COM #include <string.h>
2811044SHuie-Ying.Lee@Sun.COM #include <stdlib.h>
2911044SHuie-Ying.Lee@Sun.COM #include <stdio.h>
3011044SHuie-Ying.Lee@Sun.COM #include <stdarg.h>
3111044SHuie-Ying.Lee@Sun.COM
3211044SHuie-Ying.Lee@Sun.COM #include "match.h"
3311044SHuie-Ying.Lee@Sun.COM #include "log.h"
3411044SHuie-Ying.Lee@Sun.COM #include "xmalloc.h"
3511044SHuie-Ying.Lee@Sun.COM
3611044SHuie-Ying.Lee@Sun.COM struct xaddr {
3711044SHuie-Ying.Lee@Sun.COM sa_family_t af;
3811044SHuie-Ying.Lee@Sun.COM union {
3911044SHuie-Ying.Lee@Sun.COM struct in_addr v4;
4011044SHuie-Ying.Lee@Sun.COM struct in6_addr v6;
4111044SHuie-Ying.Lee@Sun.COM u_int8_t addr8[16];
4211044SHuie-Ying.Lee@Sun.COM u_int32_t addr32[4];
4311044SHuie-Ying.Lee@Sun.COM } xa; /* 128-bit address */
4411044SHuie-Ying.Lee@Sun.COM u_int32_t scope_id; /* iface scope id for v6 */
4511044SHuie-Ying.Lee@Sun.COM #define v4 xa.v4
4611044SHuie-Ying.Lee@Sun.COM #define v6 xa.v6
4711044SHuie-Ying.Lee@Sun.COM #define addr8 xa.addr8
4811044SHuie-Ying.Lee@Sun.COM #define addr32 xa.addr32
4911044SHuie-Ying.Lee@Sun.COM };
5011044SHuie-Ying.Lee@Sun.COM
5111044SHuie-Ying.Lee@Sun.COM static int
addr_unicast_masklen(int af)5211044SHuie-Ying.Lee@Sun.COM addr_unicast_masklen(int af)
5311044SHuie-Ying.Lee@Sun.COM {
5411044SHuie-Ying.Lee@Sun.COM switch (af) {
5511044SHuie-Ying.Lee@Sun.COM case AF_INET:
5611044SHuie-Ying.Lee@Sun.COM return 32;
5711044SHuie-Ying.Lee@Sun.COM case AF_INET6:
5811044SHuie-Ying.Lee@Sun.COM return 128;
5911044SHuie-Ying.Lee@Sun.COM default:
6011044SHuie-Ying.Lee@Sun.COM return -1;
6111044SHuie-Ying.Lee@Sun.COM }
6211044SHuie-Ying.Lee@Sun.COM }
6311044SHuie-Ying.Lee@Sun.COM
6411044SHuie-Ying.Lee@Sun.COM static inline int
masklen_valid(int af,u_int masklen)6511044SHuie-Ying.Lee@Sun.COM masklen_valid(int af, u_int masklen)
6611044SHuie-Ying.Lee@Sun.COM {
6711044SHuie-Ying.Lee@Sun.COM switch (af) {
6811044SHuie-Ying.Lee@Sun.COM case AF_INET:
6911044SHuie-Ying.Lee@Sun.COM return masklen <= 32 ? 0 : -1;
7011044SHuie-Ying.Lee@Sun.COM case AF_INET6:
7111044SHuie-Ying.Lee@Sun.COM return masklen <= 128 ? 0 : -1;
7211044SHuie-Ying.Lee@Sun.COM default:
7311044SHuie-Ying.Lee@Sun.COM return -1;
7411044SHuie-Ying.Lee@Sun.COM }
7511044SHuie-Ying.Lee@Sun.COM }
7611044SHuie-Ying.Lee@Sun.COM
7711044SHuie-Ying.Lee@Sun.COM /*
7811044SHuie-Ying.Lee@Sun.COM * Convert struct sockaddr to struct xaddr
7911044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure.
8011044SHuie-Ying.Lee@Sun.COM */
8111044SHuie-Ying.Lee@Sun.COM static int
addr_sa_to_xaddr(struct sockaddr * sa,socklen_t slen,struct xaddr * xa)8211044SHuie-Ying.Lee@Sun.COM addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
8311044SHuie-Ying.Lee@Sun.COM {
84*11060SHuie-Ying.Lee@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */
8511044SHuie-Ying.Lee@Sun.COM struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
86*11060SHuie-Ying.Lee@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */
8711044SHuie-Ying.Lee@Sun.COM struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
8811044SHuie-Ying.Lee@Sun.COM
8911044SHuie-Ying.Lee@Sun.COM memset(xa, '\0', sizeof(*xa));
9011044SHuie-Ying.Lee@Sun.COM
9111044SHuie-Ying.Lee@Sun.COM switch (sa->sa_family) {
9211044SHuie-Ying.Lee@Sun.COM case AF_INET:
9311044SHuie-Ying.Lee@Sun.COM if (slen < sizeof(*in4))
9411044SHuie-Ying.Lee@Sun.COM return -1;
9511044SHuie-Ying.Lee@Sun.COM xa->af = AF_INET;
9611044SHuie-Ying.Lee@Sun.COM memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
9711044SHuie-Ying.Lee@Sun.COM break;
9811044SHuie-Ying.Lee@Sun.COM case AF_INET6:
9911044SHuie-Ying.Lee@Sun.COM if (slen < sizeof(*in6))
10011044SHuie-Ying.Lee@Sun.COM return -1;
10111044SHuie-Ying.Lee@Sun.COM xa->af = AF_INET6;
10211044SHuie-Ying.Lee@Sun.COM memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
10311044SHuie-Ying.Lee@Sun.COM #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
10411044SHuie-Ying.Lee@Sun.COM xa->scope_id = in6->sin6_scope_id;
10511044SHuie-Ying.Lee@Sun.COM #endif
10611044SHuie-Ying.Lee@Sun.COM break;
10711044SHuie-Ying.Lee@Sun.COM default:
10811044SHuie-Ying.Lee@Sun.COM return -1;
10911044SHuie-Ying.Lee@Sun.COM }
11011044SHuie-Ying.Lee@Sun.COM
11111044SHuie-Ying.Lee@Sun.COM return 0;
11211044SHuie-Ying.Lee@Sun.COM }
11311044SHuie-Ying.Lee@Sun.COM
11411044SHuie-Ying.Lee@Sun.COM /*
11511044SHuie-Ying.Lee@Sun.COM * Calculate a netmask of length 'l' for address family 'af' and
11611044SHuie-Ying.Lee@Sun.COM * store it in 'n'.
11711044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure.
11811044SHuie-Ying.Lee@Sun.COM */
11911044SHuie-Ying.Lee@Sun.COM static int
addr_netmask(int af,u_int l,struct xaddr * n)12011044SHuie-Ying.Lee@Sun.COM addr_netmask(int af, u_int l, struct xaddr *n)
12111044SHuie-Ying.Lee@Sun.COM {
12211044SHuie-Ying.Lee@Sun.COM int i;
12311044SHuie-Ying.Lee@Sun.COM
12411044SHuie-Ying.Lee@Sun.COM if (masklen_valid(af, l) != 0 || n == NULL)
12511044SHuie-Ying.Lee@Sun.COM return -1;
12611044SHuie-Ying.Lee@Sun.COM
12711044SHuie-Ying.Lee@Sun.COM memset(n, '\0', sizeof(*n));
12811044SHuie-Ying.Lee@Sun.COM switch (af) {
12911044SHuie-Ying.Lee@Sun.COM case AF_INET:
13011044SHuie-Ying.Lee@Sun.COM n->af = AF_INET;
13111044SHuie-Ying.Lee@Sun.COM n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
13211044SHuie-Ying.Lee@Sun.COM return 0;
13311044SHuie-Ying.Lee@Sun.COM case AF_INET6:
13411044SHuie-Ying.Lee@Sun.COM n->af = AF_INET6;
13511044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4 && l >= 32; i++, l -= 32)
13611044SHuie-Ying.Lee@Sun.COM n->addr32[i] = 0xffffffffU;
13711044SHuie-Ying.Lee@Sun.COM if (i < 4 && l != 0)
13811044SHuie-Ying.Lee@Sun.COM n->addr32[i] = htonl((0xffffffff << (32 - l)) &
13911044SHuie-Ying.Lee@Sun.COM 0xffffffff);
14011044SHuie-Ying.Lee@Sun.COM return 0;
14111044SHuie-Ying.Lee@Sun.COM default:
14211044SHuie-Ying.Lee@Sun.COM return -1;
14311044SHuie-Ying.Lee@Sun.COM }
14411044SHuie-Ying.Lee@Sun.COM }
14511044SHuie-Ying.Lee@Sun.COM
14611044SHuie-Ying.Lee@Sun.COM /*
14711044SHuie-Ying.Lee@Sun.COM * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
14811044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure.
14911044SHuie-Ying.Lee@Sun.COM */
15011044SHuie-Ying.Lee@Sun.COM static int
addr_and(struct xaddr * dst,const struct xaddr * a,const struct xaddr * b)15111044SHuie-Ying.Lee@Sun.COM addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
15211044SHuie-Ying.Lee@Sun.COM {
15311044SHuie-Ying.Lee@Sun.COM int i;
15411044SHuie-Ying.Lee@Sun.COM
15511044SHuie-Ying.Lee@Sun.COM if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
15611044SHuie-Ying.Lee@Sun.COM return -1;
15711044SHuie-Ying.Lee@Sun.COM
15811044SHuie-Ying.Lee@Sun.COM memcpy(dst, a, sizeof(*dst));
15911044SHuie-Ying.Lee@Sun.COM switch (a->af) {
16011044SHuie-Ying.Lee@Sun.COM case AF_INET:
16111044SHuie-Ying.Lee@Sun.COM dst->v4.s_addr &= b->v4.s_addr;
16211044SHuie-Ying.Lee@Sun.COM return 0;
16311044SHuie-Ying.Lee@Sun.COM case AF_INET6:
16411044SHuie-Ying.Lee@Sun.COM dst->scope_id = a->scope_id;
16511044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++)
16611044SHuie-Ying.Lee@Sun.COM dst->addr32[i] &= b->addr32[i];
16711044SHuie-Ying.Lee@Sun.COM return 0;
16811044SHuie-Ying.Lee@Sun.COM default:
16911044SHuie-Ying.Lee@Sun.COM return -1;
17011044SHuie-Ying.Lee@Sun.COM }
17111044SHuie-Ying.Lee@Sun.COM }
17211044SHuie-Ying.Lee@Sun.COM
17311044SHuie-Ying.Lee@Sun.COM /*
17411044SHuie-Ying.Lee@Sun.COM * Compare addresses 'a' and 'b'
17511044SHuie-Ying.Lee@Sun.COM * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b)
17611044SHuie-Ying.Lee@Sun.COM */
17711044SHuie-Ying.Lee@Sun.COM static int
addr_cmp(const struct xaddr * a,const struct xaddr * b)17811044SHuie-Ying.Lee@Sun.COM addr_cmp(const struct xaddr *a, const struct xaddr *b)
17911044SHuie-Ying.Lee@Sun.COM {
18011044SHuie-Ying.Lee@Sun.COM int i;
18111044SHuie-Ying.Lee@Sun.COM
18211044SHuie-Ying.Lee@Sun.COM if (a->af != b->af)
18311044SHuie-Ying.Lee@Sun.COM return a->af == AF_INET6 ? 1 : -1;
18411044SHuie-Ying.Lee@Sun.COM
18511044SHuie-Ying.Lee@Sun.COM switch (a->af) {
18611044SHuie-Ying.Lee@Sun.COM case AF_INET:
18711044SHuie-Ying.Lee@Sun.COM if (a->v4.s_addr == b->v4.s_addr)
18811044SHuie-Ying.Lee@Sun.COM return 0;
18911044SHuie-Ying.Lee@Sun.COM return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1;
19011044SHuie-Ying.Lee@Sun.COM case AF_INET6:
19111044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 16; i++)
19211044SHuie-Ying.Lee@Sun.COM if (a->addr8[i] - b->addr8[i] != 0)
19311044SHuie-Ying.Lee@Sun.COM return a->addr8[i] > b->addr8[i] ? 1 : -1;
19411044SHuie-Ying.Lee@Sun.COM if (a->scope_id == b->scope_id)
19511044SHuie-Ying.Lee@Sun.COM return 0;
19611044SHuie-Ying.Lee@Sun.COM return a->scope_id > b->scope_id ? 1 : -1;
19711044SHuie-Ying.Lee@Sun.COM default:
19811044SHuie-Ying.Lee@Sun.COM return -1;
19911044SHuie-Ying.Lee@Sun.COM }
20011044SHuie-Ying.Lee@Sun.COM }
20111044SHuie-Ying.Lee@Sun.COM
20211044SHuie-Ying.Lee@Sun.COM /*
20311044SHuie-Ying.Lee@Sun.COM * Parse string address 'p' into 'n'
20411044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure.
20511044SHuie-Ying.Lee@Sun.COM */
20611044SHuie-Ying.Lee@Sun.COM static int
addr_pton(const char * p,struct xaddr * n)20711044SHuie-Ying.Lee@Sun.COM addr_pton(const char *p, struct xaddr *n)
20811044SHuie-Ying.Lee@Sun.COM {
20911044SHuie-Ying.Lee@Sun.COM struct addrinfo hints, *ai;
21011044SHuie-Ying.Lee@Sun.COM
21111044SHuie-Ying.Lee@Sun.COM memset(&hints, '\0', sizeof(hints));
21211044SHuie-Ying.Lee@Sun.COM hints.ai_flags = AI_NUMERICHOST;
21311044SHuie-Ying.Lee@Sun.COM
21411044SHuie-Ying.Lee@Sun.COM if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
21511044SHuie-Ying.Lee@Sun.COM return -1;
21611044SHuie-Ying.Lee@Sun.COM
21711044SHuie-Ying.Lee@Sun.COM if (ai == NULL || ai->ai_addr == NULL)
21811044SHuie-Ying.Lee@Sun.COM return -1;
21911044SHuie-Ying.Lee@Sun.COM
22011044SHuie-Ying.Lee@Sun.COM if (n != NULL &&
22111044SHuie-Ying.Lee@Sun.COM addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) {
22211044SHuie-Ying.Lee@Sun.COM freeaddrinfo(ai);
22311044SHuie-Ying.Lee@Sun.COM return -1;
22411044SHuie-Ying.Lee@Sun.COM }
22511044SHuie-Ying.Lee@Sun.COM
22611044SHuie-Ying.Lee@Sun.COM freeaddrinfo(ai);
22711044SHuie-Ying.Lee@Sun.COM return 0;
22811044SHuie-Ying.Lee@Sun.COM }
22911044SHuie-Ying.Lee@Sun.COM
23011044SHuie-Ying.Lee@Sun.COM /*
23111044SHuie-Ying.Lee@Sun.COM * Perform bitwise negation of address
23211044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure.
23311044SHuie-Ying.Lee@Sun.COM */
23411044SHuie-Ying.Lee@Sun.COM static int
addr_invert(struct xaddr * n)23511044SHuie-Ying.Lee@Sun.COM addr_invert(struct xaddr *n)
23611044SHuie-Ying.Lee@Sun.COM {
23711044SHuie-Ying.Lee@Sun.COM int i;
23811044SHuie-Ying.Lee@Sun.COM
23911044SHuie-Ying.Lee@Sun.COM if (n == NULL)
24011044SHuie-Ying.Lee@Sun.COM return (-1);
24111044SHuie-Ying.Lee@Sun.COM
24211044SHuie-Ying.Lee@Sun.COM switch (n->af) {
24311044SHuie-Ying.Lee@Sun.COM case AF_INET:
24411044SHuie-Ying.Lee@Sun.COM n->v4.s_addr = ~n->v4.s_addr;
24511044SHuie-Ying.Lee@Sun.COM return (0);
24611044SHuie-Ying.Lee@Sun.COM case AF_INET6:
24711044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++)
24811044SHuie-Ying.Lee@Sun.COM n->addr32[i] = ~n->addr32[i];
24911044SHuie-Ying.Lee@Sun.COM return (0);
25011044SHuie-Ying.Lee@Sun.COM default:
25111044SHuie-Ying.Lee@Sun.COM return (-1);
25211044SHuie-Ying.Lee@Sun.COM }
25311044SHuie-Ying.Lee@Sun.COM }
25411044SHuie-Ying.Lee@Sun.COM
25511044SHuie-Ying.Lee@Sun.COM /*
25611044SHuie-Ying.Lee@Sun.COM * Calculate a netmask of length 'l' for address family 'af' and
25711044SHuie-Ying.Lee@Sun.COM * store it in 'n'.
25811044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure.
25911044SHuie-Ying.Lee@Sun.COM */
26011044SHuie-Ying.Lee@Sun.COM static int
addr_hostmask(int af,u_int l,struct xaddr * n)26111044SHuie-Ying.Lee@Sun.COM addr_hostmask(int af, u_int l, struct xaddr *n)
26211044SHuie-Ying.Lee@Sun.COM {
26311044SHuie-Ying.Lee@Sun.COM if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
26411044SHuie-Ying.Lee@Sun.COM return (-1);
26511044SHuie-Ying.Lee@Sun.COM return (0);
26611044SHuie-Ying.Lee@Sun.COM }
26711044SHuie-Ying.Lee@Sun.COM
26811044SHuie-Ying.Lee@Sun.COM /*
26911044SHuie-Ying.Lee@Sun.COM * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::)
27011044SHuie-Ying.Lee@Sun.COM * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure.
27111044SHuie-Ying.Lee@Sun.COM */
27211044SHuie-Ying.Lee@Sun.COM static int
addr_is_all0s(const struct xaddr * a)27311044SHuie-Ying.Lee@Sun.COM addr_is_all0s(const struct xaddr *a)
27411044SHuie-Ying.Lee@Sun.COM {
27511044SHuie-Ying.Lee@Sun.COM int i;
27611044SHuie-Ying.Lee@Sun.COM
27711044SHuie-Ying.Lee@Sun.COM switch (a->af) {
27811044SHuie-Ying.Lee@Sun.COM case AF_INET:
27911044SHuie-Ying.Lee@Sun.COM return (a->v4.s_addr == 0 ? 0 : -1);
28011044SHuie-Ying.Lee@Sun.COM case AF_INET6:;
28111044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++)
28211044SHuie-Ying.Lee@Sun.COM if (a->addr32[i] != 0)
28311044SHuie-Ying.Lee@Sun.COM return (-1);
28411044SHuie-Ying.Lee@Sun.COM return (0);
28511044SHuie-Ying.Lee@Sun.COM default:
28611044SHuie-Ying.Lee@Sun.COM return (-1);
28711044SHuie-Ying.Lee@Sun.COM }
28811044SHuie-Ying.Lee@Sun.COM }
28911044SHuie-Ying.Lee@Sun.COM
29011044SHuie-Ying.Lee@Sun.COM /*
29111044SHuie-Ying.Lee@Sun.COM * Test whether host portion of address 'a', as determined by 'masklen'
29211044SHuie-Ying.Lee@Sun.COM * is all zeros.
29311044SHuie-Ying.Lee@Sun.COM * Returns 0 on if host portion of address is all-zeros,
29411044SHuie-Ying.Lee@Sun.COM * -1 if not all zeros or on failure.
29511044SHuie-Ying.Lee@Sun.COM */
29611044SHuie-Ying.Lee@Sun.COM static int
addr_host_is_all0s(const struct xaddr * a,u_int masklen)29711044SHuie-Ying.Lee@Sun.COM addr_host_is_all0s(const struct xaddr *a, u_int masklen)
29811044SHuie-Ying.Lee@Sun.COM {
29911044SHuie-Ying.Lee@Sun.COM struct xaddr tmp_addr, tmp_mask, tmp_result;
30011044SHuie-Ying.Lee@Sun.COM
30111044SHuie-Ying.Lee@Sun.COM memcpy(&tmp_addr, a, sizeof(tmp_addr));
30211044SHuie-Ying.Lee@Sun.COM if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
30311044SHuie-Ying.Lee@Sun.COM return (-1);
30411044SHuie-Ying.Lee@Sun.COM if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
30511044SHuie-Ying.Lee@Sun.COM return (-1);
30611044SHuie-Ying.Lee@Sun.COM return (addr_is_all0s(&tmp_result));
30711044SHuie-Ying.Lee@Sun.COM }
30811044SHuie-Ying.Lee@Sun.COM
30911044SHuie-Ying.Lee@Sun.COM /*
31011044SHuie-Ying.Lee@Sun.COM * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
31111044SHuie-Ying.Lee@Sun.COM * Return -1 on parse error, -2 on inconsistency or 0 on success.
31211044SHuie-Ying.Lee@Sun.COM */
31311044SHuie-Ying.Lee@Sun.COM static int
addr_pton_cidr(const char * p,struct xaddr * n,u_int * l)31411044SHuie-Ying.Lee@Sun.COM addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
31511044SHuie-Ying.Lee@Sun.COM {
31611044SHuie-Ying.Lee@Sun.COM struct xaddr tmp;
31711044SHuie-Ying.Lee@Sun.COM long unsigned int masklen = 999;
31811044SHuie-Ying.Lee@Sun.COM char addrbuf[64], *mp, *cp;
31911044SHuie-Ying.Lee@Sun.COM
32011044SHuie-Ying.Lee@Sun.COM /* Don't modify argument */
32111044SHuie-Ying.Lee@Sun.COM if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) > sizeof(addrbuf))
32211044SHuie-Ying.Lee@Sun.COM return -1;
32311044SHuie-Ying.Lee@Sun.COM
32411044SHuie-Ying.Lee@Sun.COM if ((mp = strchr(addrbuf, '/')) != NULL) {
32511044SHuie-Ying.Lee@Sun.COM *mp = '\0';
32611044SHuie-Ying.Lee@Sun.COM mp++;
32711044SHuie-Ying.Lee@Sun.COM masklen = strtoul(mp, &cp, 10);
32811044SHuie-Ying.Lee@Sun.COM if (*mp == '\0' || *cp != '\0' || masklen > 128)
32911044SHuie-Ying.Lee@Sun.COM return -1;
33011044SHuie-Ying.Lee@Sun.COM }
33111044SHuie-Ying.Lee@Sun.COM
33211044SHuie-Ying.Lee@Sun.COM if (addr_pton(addrbuf, &tmp) == -1)
33311044SHuie-Ying.Lee@Sun.COM return -1;
33411044SHuie-Ying.Lee@Sun.COM
33511044SHuie-Ying.Lee@Sun.COM if (mp == NULL)
33611044SHuie-Ying.Lee@Sun.COM masklen = addr_unicast_masklen(tmp.af);
33711044SHuie-Ying.Lee@Sun.COM if (masklen_valid(tmp.af, masklen) == -1)
33811044SHuie-Ying.Lee@Sun.COM return -2;
33911044SHuie-Ying.Lee@Sun.COM if (addr_host_is_all0s(&tmp, masklen) != 0)
34011044SHuie-Ying.Lee@Sun.COM return -2;
34111044SHuie-Ying.Lee@Sun.COM
34211044SHuie-Ying.Lee@Sun.COM if (n != NULL)
34311044SHuie-Ying.Lee@Sun.COM memcpy(n, &tmp, sizeof(*n));
34411044SHuie-Ying.Lee@Sun.COM if (l != NULL)
34511044SHuie-Ying.Lee@Sun.COM *l = masklen;
34611044SHuie-Ying.Lee@Sun.COM
34711044SHuie-Ying.Lee@Sun.COM return 0;
34811044SHuie-Ying.Lee@Sun.COM }
34911044SHuie-Ying.Lee@Sun.COM
35011044SHuie-Ying.Lee@Sun.COM static int
addr_netmatch(const struct xaddr * host,const struct xaddr * net,u_int masklen)35111044SHuie-Ying.Lee@Sun.COM addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
35211044SHuie-Ying.Lee@Sun.COM {
35311044SHuie-Ying.Lee@Sun.COM struct xaddr tmp_mask, tmp_result;
35411044SHuie-Ying.Lee@Sun.COM
35511044SHuie-Ying.Lee@Sun.COM if (host->af != net->af)
35611044SHuie-Ying.Lee@Sun.COM return -1;
35711044SHuie-Ying.Lee@Sun.COM
35811044SHuie-Ying.Lee@Sun.COM if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
35911044SHuie-Ying.Lee@Sun.COM return -1;
36011044SHuie-Ying.Lee@Sun.COM if (addr_and(&tmp_result, host, &tmp_mask) == -1)
36111044SHuie-Ying.Lee@Sun.COM return -1;
36211044SHuie-Ying.Lee@Sun.COM return addr_cmp(&tmp_result, net);
36311044SHuie-Ying.Lee@Sun.COM }
36411044SHuie-Ying.Lee@Sun.COM
36511044SHuie-Ying.Lee@Sun.COM /*
36611044SHuie-Ying.Lee@Sun.COM * Match "addr" against list pattern list "_list", which may contain a
36711044SHuie-Ying.Lee@Sun.COM * mix of CIDR addresses and old-school wildcards.
36811044SHuie-Ying.Lee@Sun.COM *
36911044SHuie-Ying.Lee@Sun.COM * If addr is NULL, then no matching is performed, but _list is parsed
37011044SHuie-Ying.Lee@Sun.COM * and checked for well-formedness.
37111044SHuie-Ying.Lee@Sun.COM *
37211044SHuie-Ying.Lee@Sun.COM * Returns 1 on match found (never returned when addr == NULL).
37311044SHuie-Ying.Lee@Sun.COM * Returns 0 on if no match found, or no errors found when addr == NULL.
37411044SHuie-Ying.Lee@Sun.COM * Returns -1 on negated match found (never returned when addr == NULL).
37511044SHuie-Ying.Lee@Sun.COM * Returns -2 on invalid list entry.
37611044SHuie-Ying.Lee@Sun.COM */
37711044SHuie-Ying.Lee@Sun.COM int
addr_match_list(const char * addr,const char * _list)37811044SHuie-Ying.Lee@Sun.COM addr_match_list(const char *addr, const char *_list)
37911044SHuie-Ying.Lee@Sun.COM {
38011044SHuie-Ying.Lee@Sun.COM char *list, *cp, *o;
38111044SHuie-Ying.Lee@Sun.COM struct xaddr try_addr, match_addr;
38211044SHuie-Ying.Lee@Sun.COM u_int masklen, neg;
38311044SHuie-Ying.Lee@Sun.COM int ret = 0, r;
38411044SHuie-Ying.Lee@Sun.COM
38511044SHuie-Ying.Lee@Sun.COM if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
38611044SHuie-Ying.Lee@Sun.COM debug2("%s: couldn't parse address %.100s", __func__, addr);
38711044SHuie-Ying.Lee@Sun.COM return 0;
38811044SHuie-Ying.Lee@Sun.COM }
38911044SHuie-Ying.Lee@Sun.COM if ((o = list = strdup(_list)) == NULL)
39011044SHuie-Ying.Lee@Sun.COM return -1;
39111044SHuie-Ying.Lee@Sun.COM while ((cp = strsep(&list, ",")) != NULL) {
39211044SHuie-Ying.Lee@Sun.COM neg = *cp == '!';
39311044SHuie-Ying.Lee@Sun.COM if (neg)
39411044SHuie-Ying.Lee@Sun.COM cp++;
39511044SHuie-Ying.Lee@Sun.COM if (*cp == '\0') {
39611044SHuie-Ying.Lee@Sun.COM ret = -2;
39711044SHuie-Ying.Lee@Sun.COM break;
39811044SHuie-Ying.Lee@Sun.COM }
39911044SHuie-Ying.Lee@Sun.COM /* Prefer CIDR address matching */
40011044SHuie-Ying.Lee@Sun.COM r = addr_pton_cidr(cp, &match_addr, &masklen);
40111044SHuie-Ying.Lee@Sun.COM if (r == -2) {
40211044SHuie-Ying.Lee@Sun.COM error("Inconsistent mask length for "
40311044SHuie-Ying.Lee@Sun.COM "network \"%.100s\"", cp);
40411044SHuie-Ying.Lee@Sun.COM ret = -2;
40511044SHuie-Ying.Lee@Sun.COM break;
40611044SHuie-Ying.Lee@Sun.COM } else if (r == 0) {
40711044SHuie-Ying.Lee@Sun.COM if (addr != NULL && addr_netmatch(&try_addr,
40811044SHuie-Ying.Lee@Sun.COM &match_addr, masklen) == 0) {
40911044SHuie-Ying.Lee@Sun.COM foundit:
41011044SHuie-Ying.Lee@Sun.COM if (neg) {
41111044SHuie-Ying.Lee@Sun.COM ret = -1;
41211044SHuie-Ying.Lee@Sun.COM break;
41311044SHuie-Ying.Lee@Sun.COM }
41411044SHuie-Ying.Lee@Sun.COM ret = 1;
41511044SHuie-Ying.Lee@Sun.COM }
41611044SHuie-Ying.Lee@Sun.COM continue;
41711044SHuie-Ying.Lee@Sun.COM } else {
41811044SHuie-Ying.Lee@Sun.COM /* If CIDR parse failed, try wildcard string match */
41911044SHuie-Ying.Lee@Sun.COM if (addr != NULL && match_pattern(addr, cp) == 1)
42011044SHuie-Ying.Lee@Sun.COM goto foundit;
42111044SHuie-Ying.Lee@Sun.COM }
42211044SHuie-Ying.Lee@Sun.COM }
42311044SHuie-Ying.Lee@Sun.COM xfree(o);
42411044SHuie-Ying.Lee@Sun.COM
42511044SHuie-Ying.Lee@Sun.COM return ret;
42611044SHuie-Ying.Lee@Sun.COM }
427