1*11044SHuie-Ying.Lee@Sun.COM /*	$OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk Exp $ */
2*11044SHuie-Ying.Lee@Sun.COM 
3*11044SHuie-Ying.Lee@Sun.COM /*
4*11044SHuie-Ying.Lee@Sun.COM  * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
5*11044SHuie-Ying.Lee@Sun.COM  *
6*11044SHuie-Ying.Lee@Sun.COM  * Permission to use, copy, modify, and distribute this software for any
7*11044SHuie-Ying.Lee@Sun.COM  * purpose with or without fee is hereby granted, provided that the above
8*11044SHuie-Ying.Lee@Sun.COM  * copyright notice and this permission notice appear in all copies.
9*11044SHuie-Ying.Lee@Sun.COM  *
10*11044SHuie-Ying.Lee@Sun.COM  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*11044SHuie-Ying.Lee@Sun.COM  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*11044SHuie-Ying.Lee@Sun.COM  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*11044SHuie-Ying.Lee@Sun.COM  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*11044SHuie-Ying.Lee@Sun.COM  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*11044SHuie-Ying.Lee@Sun.COM  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*11044SHuie-Ying.Lee@Sun.COM  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*11044SHuie-Ying.Lee@Sun.COM  */
18*11044SHuie-Ying.Lee@Sun.COM 
19*11044SHuie-Ying.Lee@Sun.COM #include "includes.h"
20*11044SHuie-Ying.Lee@Sun.COM 
21*11044SHuie-Ying.Lee@Sun.COM #include <sys/types.h>
22*11044SHuie-Ying.Lee@Sun.COM #include <sys/socket.h>
23*11044SHuie-Ying.Lee@Sun.COM #include <netinet/in.h>
24*11044SHuie-Ying.Lee@Sun.COM #include <arpa/inet.h>
25*11044SHuie-Ying.Lee@Sun.COM 
26*11044SHuie-Ying.Lee@Sun.COM #include <netdb.h>
27*11044SHuie-Ying.Lee@Sun.COM #include <string.h>
28*11044SHuie-Ying.Lee@Sun.COM #include <stdlib.h>
29*11044SHuie-Ying.Lee@Sun.COM #include <stdio.h>
30*11044SHuie-Ying.Lee@Sun.COM #include <stdarg.h>
31*11044SHuie-Ying.Lee@Sun.COM 
32*11044SHuie-Ying.Lee@Sun.COM #include "match.h"
33*11044SHuie-Ying.Lee@Sun.COM #include "log.h"
34*11044SHuie-Ying.Lee@Sun.COM #include "xmalloc.h"
35*11044SHuie-Ying.Lee@Sun.COM 
36*11044SHuie-Ying.Lee@Sun.COM struct xaddr {
37*11044SHuie-Ying.Lee@Sun.COM 	sa_family_t	af;
38*11044SHuie-Ying.Lee@Sun.COM 	union {
39*11044SHuie-Ying.Lee@Sun.COM 		struct in_addr		v4;
40*11044SHuie-Ying.Lee@Sun.COM 		struct in6_addr		v6;
41*11044SHuie-Ying.Lee@Sun.COM 		u_int8_t		addr8[16];
42*11044SHuie-Ying.Lee@Sun.COM 		u_int32_t		addr32[4];
43*11044SHuie-Ying.Lee@Sun.COM 	} xa;		    /* 128-bit address */
44*11044SHuie-Ying.Lee@Sun.COM 	u_int32_t	scope_id;	/* iface scope id for v6 */
45*11044SHuie-Ying.Lee@Sun.COM #define v4	xa.v4
46*11044SHuie-Ying.Lee@Sun.COM #define v6	xa.v6
47*11044SHuie-Ying.Lee@Sun.COM #define addr8	xa.addr8
48*11044SHuie-Ying.Lee@Sun.COM #define addr32	xa.addr32
49*11044SHuie-Ying.Lee@Sun.COM };
50*11044SHuie-Ying.Lee@Sun.COM 
51*11044SHuie-Ying.Lee@Sun.COM static int
52*11044SHuie-Ying.Lee@Sun.COM addr_unicast_masklen(int af)
53*11044SHuie-Ying.Lee@Sun.COM {
54*11044SHuie-Ying.Lee@Sun.COM 	switch (af) {
55*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET:
56*11044SHuie-Ying.Lee@Sun.COM 		return 32;
57*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET6:
58*11044SHuie-Ying.Lee@Sun.COM 		return 128;
59*11044SHuie-Ying.Lee@Sun.COM 	default:
60*11044SHuie-Ying.Lee@Sun.COM 		return -1;
61*11044SHuie-Ying.Lee@Sun.COM 	}
62*11044SHuie-Ying.Lee@Sun.COM }
63*11044SHuie-Ying.Lee@Sun.COM 
64*11044SHuie-Ying.Lee@Sun.COM static inline int
65*11044SHuie-Ying.Lee@Sun.COM masklen_valid(int af, u_int masklen)
66*11044SHuie-Ying.Lee@Sun.COM {
67*11044SHuie-Ying.Lee@Sun.COM 	switch (af) {
68*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET:
69*11044SHuie-Ying.Lee@Sun.COM 		return masklen <= 32 ? 0 : -1;
70*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET6:
71*11044SHuie-Ying.Lee@Sun.COM 		return masklen <= 128 ? 0 : -1;
72*11044SHuie-Ying.Lee@Sun.COM 	default:
73*11044SHuie-Ying.Lee@Sun.COM 		return -1;
74*11044SHuie-Ying.Lee@Sun.COM 	}
75*11044SHuie-Ying.Lee@Sun.COM }
76*11044SHuie-Ying.Lee@Sun.COM 
77*11044SHuie-Ying.Lee@Sun.COM /*
78*11044SHuie-Ying.Lee@Sun.COM  * Convert struct sockaddr to struct xaddr
79*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on success, -1 on failure.
80*11044SHuie-Ying.Lee@Sun.COM  */
81*11044SHuie-Ying.Lee@Sun.COM static int
82*11044SHuie-Ying.Lee@Sun.COM addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
83*11044SHuie-Ying.Lee@Sun.COM {
84*11044SHuie-Ying.Lee@Sun.COM 	struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
85*11044SHuie-Ying.Lee@Sun.COM 	struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
86*11044SHuie-Ying.Lee@Sun.COM 
87*11044SHuie-Ying.Lee@Sun.COM 	memset(xa, '\0', sizeof(*xa));
88*11044SHuie-Ying.Lee@Sun.COM 
89*11044SHuie-Ying.Lee@Sun.COM 	switch (sa->sa_family) {
90*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET:
91*11044SHuie-Ying.Lee@Sun.COM 		if (slen < sizeof(*in4))
92*11044SHuie-Ying.Lee@Sun.COM 			return -1;
93*11044SHuie-Ying.Lee@Sun.COM 		xa->af = AF_INET;
94*11044SHuie-Ying.Lee@Sun.COM 		memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
95*11044SHuie-Ying.Lee@Sun.COM 		break;
96*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET6:
97*11044SHuie-Ying.Lee@Sun.COM 		if (slen < sizeof(*in6))
98*11044SHuie-Ying.Lee@Sun.COM 			return -1;
99*11044SHuie-Ying.Lee@Sun.COM 		xa->af = AF_INET6;
100*11044SHuie-Ying.Lee@Sun.COM 		memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
101*11044SHuie-Ying.Lee@Sun.COM #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
102*11044SHuie-Ying.Lee@Sun.COM 		xa->scope_id = in6->sin6_scope_id;
103*11044SHuie-Ying.Lee@Sun.COM #endif
104*11044SHuie-Ying.Lee@Sun.COM 		break;
105*11044SHuie-Ying.Lee@Sun.COM 	default:
106*11044SHuie-Ying.Lee@Sun.COM 		return -1;
107*11044SHuie-Ying.Lee@Sun.COM 	}
108*11044SHuie-Ying.Lee@Sun.COM 
109*11044SHuie-Ying.Lee@Sun.COM 	return 0;
110*11044SHuie-Ying.Lee@Sun.COM }
111*11044SHuie-Ying.Lee@Sun.COM 
112*11044SHuie-Ying.Lee@Sun.COM /*
113*11044SHuie-Ying.Lee@Sun.COM  * Calculate a netmask of length 'l' for address family 'af' and
114*11044SHuie-Ying.Lee@Sun.COM  * store it in 'n'.
115*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on success, -1 on failure.
116*11044SHuie-Ying.Lee@Sun.COM  */
117*11044SHuie-Ying.Lee@Sun.COM static int
118*11044SHuie-Ying.Lee@Sun.COM addr_netmask(int af, u_int l, struct xaddr *n)
119*11044SHuie-Ying.Lee@Sun.COM {
120*11044SHuie-Ying.Lee@Sun.COM 	int i;
121*11044SHuie-Ying.Lee@Sun.COM 
122*11044SHuie-Ying.Lee@Sun.COM 	if (masklen_valid(af, l) != 0 || n == NULL)
123*11044SHuie-Ying.Lee@Sun.COM 		return -1;
124*11044SHuie-Ying.Lee@Sun.COM 
125*11044SHuie-Ying.Lee@Sun.COM 	memset(n, '\0', sizeof(*n));
126*11044SHuie-Ying.Lee@Sun.COM 	switch (af) {
127*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET:
128*11044SHuie-Ying.Lee@Sun.COM 		n->af = AF_INET;
129*11044SHuie-Ying.Lee@Sun.COM 		n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
130*11044SHuie-Ying.Lee@Sun.COM 		return 0;
131*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET6:
132*11044SHuie-Ying.Lee@Sun.COM 		n->af = AF_INET6;
133*11044SHuie-Ying.Lee@Sun.COM 		for (i = 0; i < 4 && l >= 32; i++, l -= 32)
134*11044SHuie-Ying.Lee@Sun.COM 			n->addr32[i] = 0xffffffffU;
135*11044SHuie-Ying.Lee@Sun.COM 		if (i < 4 && l != 0)
136*11044SHuie-Ying.Lee@Sun.COM 			n->addr32[i] = htonl((0xffffffff << (32 - l)) &
137*11044SHuie-Ying.Lee@Sun.COM 			    0xffffffff);
138*11044SHuie-Ying.Lee@Sun.COM 		return 0;
139*11044SHuie-Ying.Lee@Sun.COM 	default:
140*11044SHuie-Ying.Lee@Sun.COM 		return -1;
141*11044SHuie-Ying.Lee@Sun.COM 	}
142*11044SHuie-Ying.Lee@Sun.COM }
143*11044SHuie-Ying.Lee@Sun.COM 
144*11044SHuie-Ying.Lee@Sun.COM /*
145*11044SHuie-Ying.Lee@Sun.COM  * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
146*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on success, -1 on failure.
147*11044SHuie-Ying.Lee@Sun.COM  */
148*11044SHuie-Ying.Lee@Sun.COM static int
149*11044SHuie-Ying.Lee@Sun.COM addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
150*11044SHuie-Ying.Lee@Sun.COM {
151*11044SHuie-Ying.Lee@Sun.COM 	int i;
152*11044SHuie-Ying.Lee@Sun.COM 
153*11044SHuie-Ying.Lee@Sun.COM 	if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
154*11044SHuie-Ying.Lee@Sun.COM 		return -1;
155*11044SHuie-Ying.Lee@Sun.COM 
156*11044SHuie-Ying.Lee@Sun.COM 	memcpy(dst, a, sizeof(*dst));
157*11044SHuie-Ying.Lee@Sun.COM 	switch (a->af) {
158*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET:
159*11044SHuie-Ying.Lee@Sun.COM 		dst->v4.s_addr &= b->v4.s_addr;
160*11044SHuie-Ying.Lee@Sun.COM 		return 0;
161*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET6:
162*11044SHuie-Ying.Lee@Sun.COM 		dst->scope_id = a->scope_id;
163*11044SHuie-Ying.Lee@Sun.COM 		for (i = 0; i < 4; i++)
164*11044SHuie-Ying.Lee@Sun.COM 			dst->addr32[i] &= b->addr32[i];
165*11044SHuie-Ying.Lee@Sun.COM 		return 0;
166*11044SHuie-Ying.Lee@Sun.COM 	default:
167*11044SHuie-Ying.Lee@Sun.COM 		return -1;
168*11044SHuie-Ying.Lee@Sun.COM 	}
169*11044SHuie-Ying.Lee@Sun.COM }
170*11044SHuie-Ying.Lee@Sun.COM 
171*11044SHuie-Ying.Lee@Sun.COM /*
172*11044SHuie-Ying.Lee@Sun.COM  * Compare addresses 'a' and 'b'
173*11044SHuie-Ying.Lee@Sun.COM  * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b)
174*11044SHuie-Ying.Lee@Sun.COM  */
175*11044SHuie-Ying.Lee@Sun.COM static int
176*11044SHuie-Ying.Lee@Sun.COM addr_cmp(const struct xaddr *a, const struct xaddr *b)
177*11044SHuie-Ying.Lee@Sun.COM {
178*11044SHuie-Ying.Lee@Sun.COM 	int i;
179*11044SHuie-Ying.Lee@Sun.COM 
180*11044SHuie-Ying.Lee@Sun.COM 	if (a->af != b->af)
181*11044SHuie-Ying.Lee@Sun.COM 		return a->af == AF_INET6 ? 1 : -1;
182*11044SHuie-Ying.Lee@Sun.COM 
183*11044SHuie-Ying.Lee@Sun.COM 	switch (a->af) {
184*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET:
185*11044SHuie-Ying.Lee@Sun.COM 		if (a->v4.s_addr == b->v4.s_addr)
186*11044SHuie-Ying.Lee@Sun.COM 			return 0;
187*11044SHuie-Ying.Lee@Sun.COM 		return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1;
188*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET6:
189*11044SHuie-Ying.Lee@Sun.COM 		for (i = 0; i < 16; i++)
190*11044SHuie-Ying.Lee@Sun.COM 			if (a->addr8[i] - b->addr8[i] != 0)
191*11044SHuie-Ying.Lee@Sun.COM 				return a->addr8[i] > b->addr8[i] ? 1 : -1;
192*11044SHuie-Ying.Lee@Sun.COM 		if (a->scope_id == b->scope_id)
193*11044SHuie-Ying.Lee@Sun.COM 			return 0;
194*11044SHuie-Ying.Lee@Sun.COM 		return a->scope_id > b->scope_id ? 1 : -1;
195*11044SHuie-Ying.Lee@Sun.COM 	default:
196*11044SHuie-Ying.Lee@Sun.COM 		return -1;
197*11044SHuie-Ying.Lee@Sun.COM 	}
198*11044SHuie-Ying.Lee@Sun.COM }
199*11044SHuie-Ying.Lee@Sun.COM 
200*11044SHuie-Ying.Lee@Sun.COM /*
201*11044SHuie-Ying.Lee@Sun.COM  * Parse string address 'p' into 'n'
202*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on success, -1 on failure.
203*11044SHuie-Ying.Lee@Sun.COM  */
204*11044SHuie-Ying.Lee@Sun.COM static int
205*11044SHuie-Ying.Lee@Sun.COM addr_pton(const char *p, struct xaddr *n)
206*11044SHuie-Ying.Lee@Sun.COM {
207*11044SHuie-Ying.Lee@Sun.COM 	struct addrinfo hints, *ai;
208*11044SHuie-Ying.Lee@Sun.COM 
209*11044SHuie-Ying.Lee@Sun.COM 	memset(&hints, '\0', sizeof(hints));
210*11044SHuie-Ying.Lee@Sun.COM 	hints.ai_flags = AI_NUMERICHOST;
211*11044SHuie-Ying.Lee@Sun.COM 
212*11044SHuie-Ying.Lee@Sun.COM 	if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
213*11044SHuie-Ying.Lee@Sun.COM 		return -1;
214*11044SHuie-Ying.Lee@Sun.COM 
215*11044SHuie-Ying.Lee@Sun.COM 	if (ai == NULL || ai->ai_addr == NULL)
216*11044SHuie-Ying.Lee@Sun.COM 		return -1;
217*11044SHuie-Ying.Lee@Sun.COM 
218*11044SHuie-Ying.Lee@Sun.COM 	if (n != NULL &&
219*11044SHuie-Ying.Lee@Sun.COM 	    addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) {
220*11044SHuie-Ying.Lee@Sun.COM 		freeaddrinfo(ai);
221*11044SHuie-Ying.Lee@Sun.COM 		return -1;
222*11044SHuie-Ying.Lee@Sun.COM 	}
223*11044SHuie-Ying.Lee@Sun.COM 
224*11044SHuie-Ying.Lee@Sun.COM 	freeaddrinfo(ai);
225*11044SHuie-Ying.Lee@Sun.COM 	return 0;
226*11044SHuie-Ying.Lee@Sun.COM }
227*11044SHuie-Ying.Lee@Sun.COM 
228*11044SHuie-Ying.Lee@Sun.COM /*
229*11044SHuie-Ying.Lee@Sun.COM  * Perform bitwise negation of address
230*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on success, -1 on failure.
231*11044SHuie-Ying.Lee@Sun.COM  */
232*11044SHuie-Ying.Lee@Sun.COM static int
233*11044SHuie-Ying.Lee@Sun.COM addr_invert(struct xaddr *n)
234*11044SHuie-Ying.Lee@Sun.COM {
235*11044SHuie-Ying.Lee@Sun.COM 	int i;
236*11044SHuie-Ying.Lee@Sun.COM 
237*11044SHuie-Ying.Lee@Sun.COM 	if (n == NULL)
238*11044SHuie-Ying.Lee@Sun.COM 		return (-1);
239*11044SHuie-Ying.Lee@Sun.COM 
240*11044SHuie-Ying.Lee@Sun.COM 	switch (n->af) {
241*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET:
242*11044SHuie-Ying.Lee@Sun.COM 		n->v4.s_addr = ~n->v4.s_addr;
243*11044SHuie-Ying.Lee@Sun.COM 		return (0);
244*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET6:
245*11044SHuie-Ying.Lee@Sun.COM 		for (i = 0; i < 4; i++)
246*11044SHuie-Ying.Lee@Sun.COM 			n->addr32[i] = ~n->addr32[i];
247*11044SHuie-Ying.Lee@Sun.COM 		return (0);
248*11044SHuie-Ying.Lee@Sun.COM 	default:
249*11044SHuie-Ying.Lee@Sun.COM 		return (-1);
250*11044SHuie-Ying.Lee@Sun.COM 	}
251*11044SHuie-Ying.Lee@Sun.COM }
252*11044SHuie-Ying.Lee@Sun.COM 
253*11044SHuie-Ying.Lee@Sun.COM /*
254*11044SHuie-Ying.Lee@Sun.COM  * Calculate a netmask of length 'l' for address family 'af' and
255*11044SHuie-Ying.Lee@Sun.COM  * store it in 'n'.
256*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on success, -1 on failure.
257*11044SHuie-Ying.Lee@Sun.COM  */
258*11044SHuie-Ying.Lee@Sun.COM static int
259*11044SHuie-Ying.Lee@Sun.COM addr_hostmask(int af, u_int l, struct xaddr *n)
260*11044SHuie-Ying.Lee@Sun.COM {
261*11044SHuie-Ying.Lee@Sun.COM 	if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
262*11044SHuie-Ying.Lee@Sun.COM 		return (-1);
263*11044SHuie-Ying.Lee@Sun.COM 	return (0);
264*11044SHuie-Ying.Lee@Sun.COM }
265*11044SHuie-Ying.Lee@Sun.COM 
266*11044SHuie-Ying.Lee@Sun.COM /*
267*11044SHuie-Ying.Lee@Sun.COM  * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::)
268*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure.
269*11044SHuie-Ying.Lee@Sun.COM  */
270*11044SHuie-Ying.Lee@Sun.COM static int
271*11044SHuie-Ying.Lee@Sun.COM addr_is_all0s(const struct xaddr *a)
272*11044SHuie-Ying.Lee@Sun.COM {
273*11044SHuie-Ying.Lee@Sun.COM 	int i;
274*11044SHuie-Ying.Lee@Sun.COM 
275*11044SHuie-Ying.Lee@Sun.COM 	switch (a->af) {
276*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET:
277*11044SHuie-Ying.Lee@Sun.COM 		return (a->v4.s_addr == 0 ? 0 : -1);
278*11044SHuie-Ying.Lee@Sun.COM 	case AF_INET6:;
279*11044SHuie-Ying.Lee@Sun.COM 		for (i = 0; i < 4; i++)
280*11044SHuie-Ying.Lee@Sun.COM 			if (a->addr32[i] != 0)
281*11044SHuie-Ying.Lee@Sun.COM 				return (-1);
282*11044SHuie-Ying.Lee@Sun.COM 		return (0);
283*11044SHuie-Ying.Lee@Sun.COM 	default:
284*11044SHuie-Ying.Lee@Sun.COM 		return (-1);
285*11044SHuie-Ying.Lee@Sun.COM 	}
286*11044SHuie-Ying.Lee@Sun.COM }
287*11044SHuie-Ying.Lee@Sun.COM 
288*11044SHuie-Ying.Lee@Sun.COM /*
289*11044SHuie-Ying.Lee@Sun.COM  * Test whether host portion of address 'a', as determined by 'masklen'
290*11044SHuie-Ying.Lee@Sun.COM  * is all zeros.
291*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on if host portion of address is all-zeros,
292*11044SHuie-Ying.Lee@Sun.COM  * -1 if not all zeros or on failure.
293*11044SHuie-Ying.Lee@Sun.COM  */
294*11044SHuie-Ying.Lee@Sun.COM static int
295*11044SHuie-Ying.Lee@Sun.COM addr_host_is_all0s(const struct xaddr *a, u_int masklen)
296*11044SHuie-Ying.Lee@Sun.COM {
297*11044SHuie-Ying.Lee@Sun.COM 	struct xaddr tmp_addr, tmp_mask, tmp_result;
298*11044SHuie-Ying.Lee@Sun.COM 
299*11044SHuie-Ying.Lee@Sun.COM 	memcpy(&tmp_addr, a, sizeof(tmp_addr));
300*11044SHuie-Ying.Lee@Sun.COM 	if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
301*11044SHuie-Ying.Lee@Sun.COM 		return (-1);
302*11044SHuie-Ying.Lee@Sun.COM 	if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
303*11044SHuie-Ying.Lee@Sun.COM 		return (-1);
304*11044SHuie-Ying.Lee@Sun.COM 	return (addr_is_all0s(&tmp_result));
305*11044SHuie-Ying.Lee@Sun.COM }
306*11044SHuie-Ying.Lee@Sun.COM 
307*11044SHuie-Ying.Lee@Sun.COM /*
308*11044SHuie-Ying.Lee@Sun.COM  * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
309*11044SHuie-Ying.Lee@Sun.COM  * Return -1 on parse error, -2 on inconsistency or 0 on success.
310*11044SHuie-Ying.Lee@Sun.COM  */
311*11044SHuie-Ying.Lee@Sun.COM static int
312*11044SHuie-Ying.Lee@Sun.COM addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
313*11044SHuie-Ying.Lee@Sun.COM {
314*11044SHuie-Ying.Lee@Sun.COM 	struct xaddr tmp;
315*11044SHuie-Ying.Lee@Sun.COM 	long unsigned int masklen = 999;
316*11044SHuie-Ying.Lee@Sun.COM 	char addrbuf[64], *mp, *cp;
317*11044SHuie-Ying.Lee@Sun.COM 
318*11044SHuie-Ying.Lee@Sun.COM 	/* Don't modify argument */
319*11044SHuie-Ying.Lee@Sun.COM 	if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) > sizeof(addrbuf))
320*11044SHuie-Ying.Lee@Sun.COM 		return -1;
321*11044SHuie-Ying.Lee@Sun.COM 
322*11044SHuie-Ying.Lee@Sun.COM 	if ((mp = strchr(addrbuf, '/')) != NULL) {
323*11044SHuie-Ying.Lee@Sun.COM 		*mp = '\0';
324*11044SHuie-Ying.Lee@Sun.COM 		mp++;
325*11044SHuie-Ying.Lee@Sun.COM 		masklen = strtoul(mp, &cp, 10);
326*11044SHuie-Ying.Lee@Sun.COM 		if (*mp == '\0' || *cp != '\0' || masklen > 128)
327*11044SHuie-Ying.Lee@Sun.COM 			return -1;
328*11044SHuie-Ying.Lee@Sun.COM 	}
329*11044SHuie-Ying.Lee@Sun.COM 
330*11044SHuie-Ying.Lee@Sun.COM 	if (addr_pton(addrbuf, &tmp) == -1)
331*11044SHuie-Ying.Lee@Sun.COM 		return -1;
332*11044SHuie-Ying.Lee@Sun.COM 
333*11044SHuie-Ying.Lee@Sun.COM 	if (mp == NULL)
334*11044SHuie-Ying.Lee@Sun.COM 		masklen = addr_unicast_masklen(tmp.af);
335*11044SHuie-Ying.Lee@Sun.COM 	if (masklen_valid(tmp.af, masklen) == -1)
336*11044SHuie-Ying.Lee@Sun.COM 		return -2;
337*11044SHuie-Ying.Lee@Sun.COM 	if (addr_host_is_all0s(&tmp, masklen) != 0)
338*11044SHuie-Ying.Lee@Sun.COM 		return -2;
339*11044SHuie-Ying.Lee@Sun.COM 
340*11044SHuie-Ying.Lee@Sun.COM 	if (n != NULL)
341*11044SHuie-Ying.Lee@Sun.COM 		memcpy(n, &tmp, sizeof(*n));
342*11044SHuie-Ying.Lee@Sun.COM 	if (l != NULL)
343*11044SHuie-Ying.Lee@Sun.COM 		*l = masklen;
344*11044SHuie-Ying.Lee@Sun.COM 
345*11044SHuie-Ying.Lee@Sun.COM 	return 0;
346*11044SHuie-Ying.Lee@Sun.COM }
347*11044SHuie-Ying.Lee@Sun.COM 
348*11044SHuie-Ying.Lee@Sun.COM static int
349*11044SHuie-Ying.Lee@Sun.COM addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
350*11044SHuie-Ying.Lee@Sun.COM {
351*11044SHuie-Ying.Lee@Sun.COM 	struct xaddr tmp_mask, tmp_result;
352*11044SHuie-Ying.Lee@Sun.COM 
353*11044SHuie-Ying.Lee@Sun.COM 	if (host->af != net->af)
354*11044SHuie-Ying.Lee@Sun.COM 		return -1;
355*11044SHuie-Ying.Lee@Sun.COM 
356*11044SHuie-Ying.Lee@Sun.COM 	if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
357*11044SHuie-Ying.Lee@Sun.COM 		return -1;
358*11044SHuie-Ying.Lee@Sun.COM 	if (addr_and(&tmp_result, host, &tmp_mask) == -1)
359*11044SHuie-Ying.Lee@Sun.COM 		return -1;
360*11044SHuie-Ying.Lee@Sun.COM 	return addr_cmp(&tmp_result, net);
361*11044SHuie-Ying.Lee@Sun.COM }
362*11044SHuie-Ying.Lee@Sun.COM 
363*11044SHuie-Ying.Lee@Sun.COM /*
364*11044SHuie-Ying.Lee@Sun.COM  * Match "addr" against list pattern list "_list", which may contain a
365*11044SHuie-Ying.Lee@Sun.COM  * mix of CIDR addresses and old-school wildcards.
366*11044SHuie-Ying.Lee@Sun.COM  *
367*11044SHuie-Ying.Lee@Sun.COM  * If addr is NULL, then no matching is performed, but _list is parsed
368*11044SHuie-Ying.Lee@Sun.COM  * and checked for well-formedness.
369*11044SHuie-Ying.Lee@Sun.COM  *
370*11044SHuie-Ying.Lee@Sun.COM  * Returns 1 on match found (never returned when addr == NULL).
371*11044SHuie-Ying.Lee@Sun.COM  * Returns 0 on if no match found, or no errors found when addr == NULL.
372*11044SHuie-Ying.Lee@Sun.COM  * Returns -1 on negated match found (never returned when addr == NULL).
373*11044SHuie-Ying.Lee@Sun.COM  * Returns -2 on invalid list entry.
374*11044SHuie-Ying.Lee@Sun.COM  */
375*11044SHuie-Ying.Lee@Sun.COM int
376*11044SHuie-Ying.Lee@Sun.COM addr_match_list(const char *addr, const char *_list)
377*11044SHuie-Ying.Lee@Sun.COM {
378*11044SHuie-Ying.Lee@Sun.COM 	char *list, *cp, *o;
379*11044SHuie-Ying.Lee@Sun.COM 	struct xaddr try_addr, match_addr;
380*11044SHuie-Ying.Lee@Sun.COM 	u_int masklen, neg;
381*11044SHuie-Ying.Lee@Sun.COM 	int ret = 0, r;
382*11044SHuie-Ying.Lee@Sun.COM 
383*11044SHuie-Ying.Lee@Sun.COM 	if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
384*11044SHuie-Ying.Lee@Sun.COM 		debug2("%s: couldn't parse address %.100s", __func__, addr);
385*11044SHuie-Ying.Lee@Sun.COM 		return 0;
386*11044SHuie-Ying.Lee@Sun.COM 	}
387*11044SHuie-Ying.Lee@Sun.COM 	if ((o = list = strdup(_list)) == NULL)
388*11044SHuie-Ying.Lee@Sun.COM 		return -1;
389*11044SHuie-Ying.Lee@Sun.COM 	while ((cp = strsep(&list, ",")) != NULL) {
390*11044SHuie-Ying.Lee@Sun.COM 		neg = *cp == '!';
391*11044SHuie-Ying.Lee@Sun.COM 		if (neg)
392*11044SHuie-Ying.Lee@Sun.COM 			cp++;
393*11044SHuie-Ying.Lee@Sun.COM 		if (*cp == '\0') {
394*11044SHuie-Ying.Lee@Sun.COM 			ret = -2;
395*11044SHuie-Ying.Lee@Sun.COM 			break;
396*11044SHuie-Ying.Lee@Sun.COM 		}
397*11044SHuie-Ying.Lee@Sun.COM 		/* Prefer CIDR address matching */
398*11044SHuie-Ying.Lee@Sun.COM 		r = addr_pton_cidr(cp, &match_addr, &masklen);
399*11044SHuie-Ying.Lee@Sun.COM 		if (r == -2) {
400*11044SHuie-Ying.Lee@Sun.COM 			error("Inconsistent mask length for "
401*11044SHuie-Ying.Lee@Sun.COM 			    "network \"%.100s\"", cp);
402*11044SHuie-Ying.Lee@Sun.COM 			ret = -2;
403*11044SHuie-Ying.Lee@Sun.COM 			break;
404*11044SHuie-Ying.Lee@Sun.COM 		} else if (r == 0) {
405*11044SHuie-Ying.Lee@Sun.COM 			if (addr != NULL && addr_netmatch(&try_addr,
406*11044SHuie-Ying.Lee@Sun.COM                            &match_addr, masklen) == 0) {
407*11044SHuie-Ying.Lee@Sun.COM  foundit:
408*11044SHuie-Ying.Lee@Sun.COM 				if (neg) {
409*11044SHuie-Ying.Lee@Sun.COM 					ret = -1;
410*11044SHuie-Ying.Lee@Sun.COM 					break;
411*11044SHuie-Ying.Lee@Sun.COM 				}
412*11044SHuie-Ying.Lee@Sun.COM 				ret = 1;
413*11044SHuie-Ying.Lee@Sun.COM 			}
414*11044SHuie-Ying.Lee@Sun.COM 			continue;
415*11044SHuie-Ying.Lee@Sun.COM 		} else {
416*11044SHuie-Ying.Lee@Sun.COM 			/* If CIDR parse failed, try wildcard string match */
417*11044SHuie-Ying.Lee@Sun.COM 			if (addr != NULL && match_pattern(addr, cp) == 1)
418*11044SHuie-Ying.Lee@Sun.COM 				goto foundit;
419*11044SHuie-Ying.Lee@Sun.COM 		}
420*11044SHuie-Ying.Lee@Sun.COM 	}
421*11044SHuie-Ying.Lee@Sun.COM 	xfree(o);
422*11044SHuie-Ying.Lee@Sun.COM 
423*11044SHuie-Ying.Lee@Sun.COM 	return ret;
424*11044SHuie-Ying.Lee@Sun.COM }
425