Branch data Line data Source code
1 : : /* $OpenBSD: addrmatch.c,v 1.9 2014/01/19 11:21:51 dtucker Exp $ */
2 : :
3 : : /*
4 : : * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
5 : : *
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.
9 : : *
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.
17 : : */
18 : :
19 : : #include "includes.h"
20 : :
21 : : #include <sys/types.h>
22 : : #include <sys/socket.h>
23 : : #include <netinet/in.h>
24 : : #include <arpa/inet.h>
25 : :
26 : : #include <netdb.h>
27 : : #include <string.h>
28 : : #include <stdlib.h>
29 : : #include <stdio.h>
30 : : #include <stdarg.h>
31 : :
32 : : #include "match.h"
33 : : #include "log.h"
34 : : #include "xmalloc.h"
35 : :
36 : : struct xaddr {
37 : : sa_family_t af;
38 : : union {
39 : : struct in_addr v4;
40 : : struct in6_addr v6;
41 : : u_int8_t addr8[16];
42 : : u_int32_t addr32[4];
43 : : } xa; /* 128-bit address */
44 : : u_int32_t scope_id; /* iface scope id for v6 */
45 : : #define v4 xa.v4
46 : : #define v6 xa.v6
47 : : #define addr8 xa.addr8
48 : : #define addr32 xa.addr32
49 : : };
50 : :
51 : : static int
52 : : addr_unicast_masklen(int af)
53 : : {
54 [ + - + ]: 93 : switch (af) {
55 : : case AF_INET:
56 : : return 32;
57 : : case AF_INET6:
58 : : return 128;
59 : : default:
60 : : return -1;
61 : : }
62 : : }
63 : :
64 : : static inline int
65 : : masklen_valid(int af, u_int masklen)
66 : : {
67 [ + + - ]: 407 : switch (af) {
[ + + - ]
68 : : case AF_INET:
69 [ - + ][ - + ]: 250 : return masklen <= 32 ? 0 : -1;
70 : : case AF_INET6:
71 [ - + ][ - + ]: 157 : return masklen <= 128 ? 0 : -1;
72 : : default:
73 : : return -1;
74 : : }
75 : : }
76 : :
77 : : /*
78 : : * Convert struct sockaddr to struct xaddr
79 : : * Returns 0 on success, -1 on failure.
80 : : */
81 : : static int
82 : 225 : addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
83 : : {
84 : 225 : struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
85 : 225 : struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
86 : :
87 : : memset(xa, '\0', sizeof(*xa));
88 : :
89 [ + + - ]: 225 : switch (sa->sa_family) {
90 : : case AF_INET:
91 [ + - ]: 138 : if (slen < (socklen_t)sizeof(*in4))
92 : : return -1;
93 : 138 : xa->af = AF_INET;
94 : 138 : memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
95 : : break;
96 : : case AF_INET6:
97 [ + - ]: 87 : if (slen < (socklen_t)sizeof(*in6))
98 : : return -1;
99 : 87 : xa->af = AF_INET6;
100 : 87 : memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
101 : : #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
102 : 87 : xa->scope_id = in6->sin6_scope_id;
103 : : #endif
104 : 87 : break;
105 : : default:
106 : : return -1;
107 : : }
108 : :
109 : : return 0;
110 : : }
111 : :
112 : : /*
113 : : * Calculate a netmask of length 'l' for address family 'af' and
114 : : * store it in 'n'.
115 : : * Returns 0 on success, -1 on failure.
116 : : */
117 : : static int
118 : 246 : addr_netmask(int af, u_int l, struct xaddr *n)
119 : : {
120 : : int i;
121 : :
122 [ + - ][ + - ]: 246 : if (masklen_valid(af, l) != 0 || n == NULL)
123 : : return -1;
124 : :
125 : : memset(n, '\0', sizeof(*n));
126 [ + + - ]: 246 : switch (af) {
127 : : case AF_INET:
128 : 152 : n->af = AF_INET;
129 [ + - ]: 152 : if (l == 0)
130 : : return 0;
131 : 304 : n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
132 : 152 : return 0;
133 : : case AF_INET6:
134 : 94 : n->af = AF_INET6;
135 [ + + ]: 382 : for (i = 0; i < 4 && l >= 32; i++, l -= 32)
136 : 288 : n->addr32[i] = 0xffffffffU;
137 [ + + ]: 94 : if (i < 4 && l != 0)
138 : 22 : n->addr32[i] = htonl((0xffffffff << (32 - l)) &
139 : : 0xffffffff);
140 : : return 0;
141 : : default:
142 : : return -1;
143 : : }
144 : : }
145 : :
146 : : /*
147 : : * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
148 : : * Returns 0 on success, -1 on failure.
149 : : */
150 : : static int
151 : 246 : addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
152 : : {
153 : : int i;
154 : :
155 [ + - ][ + - ]: 246 : if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
[ + - ]
156 : : return -1;
157 : :
158 : : memcpy(dst, a, sizeof(*dst));
159 [ + + - ]: 246 : switch (a->af) {
160 : : case AF_INET:
161 : 152 : dst->v4.s_addr &= b->v4.s_addr;
162 : 152 : return 0;
163 : : case AF_INET6:
164 : 94 : dst->scope_id = a->scope_id;
165 [ + + ]: 470 : for (i = 0; i < 4; i++)
166 : 376 : dst->addr32[i] &= b->addr32[i];
167 : : return 0;
168 : : default:
169 : : return -1;
170 : : }
171 : : }
172 : :
173 : : /*
174 : : * Compare addresses 'a' and 'b'
175 : : * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b)
176 : : */
177 : : static int
178 : 85 : addr_cmp(const struct xaddr *a, const struct xaddr *b)
179 : : {
180 : : int i;
181 : :
182 [ - + ]: 85 : if (a->af != b->af)
183 [ # # ]: 0 : return a->af == AF_INET6 ? 1 : -1;
184 : :
185 [ + + - ]: 85 : switch (a->af) {
186 : : case AF_INET:
187 [ + + ]: 54 : if (a->v4.s_addr == b->v4.s_addr)
188 : : return 0;
189 [ + + ]: 30 : return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1;
190 : : case AF_INET6:
191 [ + + ]: 351 : for (i = 0; i < 16; i++)
192 [ + + ]: 347 : if (a->addr8[i] - b->addr8[i] != 0)
193 [ + + ]: 27 : return a->addr8[i] > b->addr8[i] ? 1 : -1;
194 [ - + ]: 4 : if (a->scope_id == b->scope_id)
195 : : return 0;
196 [ # # ]: 0 : return a->scope_id > b->scope_id ? 1 : -1;
197 : : default:
198 : : return -1;
199 : : }
200 : : }
201 : :
202 : : /*
203 : : * Parse string address 'p' into 'n'
204 : : * Returns 0 on success, -1 on failure.
205 : : */
206 : : static int
207 : 243 : addr_pton(const char *p, struct xaddr *n)
208 : : {
209 : : struct addrinfo hints, *ai;
210 : :
211 : : memset(&hints, '\0', sizeof(hints));
212 : 243 : hints.ai_flags = AI_NUMERICHOST;
213 : :
214 [ + - ][ + + ]: 243 : if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
215 : : return -1;
216 : :
217 [ + - ][ + - ]: 225 : if (ai == NULL || ai->ai_addr == NULL)
218 : : return -1;
219 : :
220 [ + - - + ]: 450 : if (n != NULL &&
221 : 225 : addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) {
222 : 0 : freeaddrinfo(ai);
223 : 0 : return -1;
224 : : }
225 : :
226 : 225 : freeaddrinfo(ai);
227 : 225 : return 0;
228 : : }
229 : :
230 : : /*
231 : : * Perform bitwise negation of address
232 : : * Returns 0 on success, -1 on failure.
233 : : */
234 : : static int
235 : 161 : addr_invert(struct xaddr *n)
236 : : {
237 : : int i;
238 : :
239 [ + - ]: 161 : if (n == NULL)
240 : : return (-1);
241 : :
242 [ + + - ]: 161 : switch (n->af) {
243 : : case AF_INET:
244 : 98 : n->v4.s_addr = ~n->v4.s_addr;
245 : 98 : return (0);
246 : : case AF_INET6:
247 [ + + ]: 315 : for (i = 0; i < 4; i++)
248 : 252 : n->addr32[i] = ~n->addr32[i];
249 : : return (0);
250 : : default:
251 : : return (-1);
252 : : }
253 : : }
254 : :
255 : : /*
256 : : * Calculate a netmask of length 'l' for address family 'af' and
257 : : * store it in 'n'.
258 : : * Returns 0 on success, -1 on failure.
259 : : */
260 : : static int
261 : 161 : addr_hostmask(int af, u_int l, struct xaddr *n)
262 : : {
263 [ + - ][ - + ]: 161 : if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
264 : : return (-1);
265 : : return (0);
266 : : }
267 : :
268 : : /*
269 : : * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::)
270 : : * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure.
271 : : */
272 : : static int
273 : 161 : addr_is_all0s(const struct xaddr *a)
274 : : {
275 : : int i;
276 : :
277 [ + + - ]: 161 : switch (a->af) {
278 : : case AF_INET:
279 [ - + ]: 98 : return (a->v4.s_addr == 0 ? 0 : -1);
280 : : case AF_INET6:;
281 [ + + ]: 315 : for (i = 0; i < 4; i++)
282 [ + - ]: 252 : if (a->addr32[i] != 0)
283 : : return (-1);
284 : : return (0);
285 : : default:
286 : : return (-1);
287 : : }
288 : : }
289 : :
290 : : /*
291 : : * Test whether host portion of address 'a', as determined by 'masklen'
292 : : * is all zeros.
293 : : * Returns 0 on if host portion of address is all-zeros,
294 : : * -1 if not all zeros or on failure.
295 : : */
296 : : static int
297 : 161 : addr_host_is_all0s(const struct xaddr *a, u_int masklen)
298 : : {
299 : : struct xaddr tmp_addr, tmp_mask, tmp_result;
300 : :
301 : : memcpy(&tmp_addr, a, sizeof(tmp_addr));
302 [ + - ]: 161 : if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
303 : : return (-1);
304 [ + - ]: 161 : if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
305 : : return (-1);
306 : 161 : return (addr_is_all0s(&tmp_result));
307 : : }
308 : :
309 : : /*
310 : : * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
311 : : * Return -1 on parse error, -2 on inconsistency or 0 on success.
312 : : */
313 : : static int
314 : 175 : addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
315 : : {
316 : : struct xaddr tmp;
317 : 175 : long unsigned int masklen = 999;
318 : : char addrbuf[64], *mp, *cp;
319 : :
320 : : /* Don't modify argument */
321 [ + - ][ + - ]: 175 : if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) >= sizeof(addrbuf))
322 : : return -1;
323 : :
324 [ + + ]: 175 : if ((mp = strchr(addrbuf, '/')) != NULL) {
325 : 68 : *mp = '\0';
326 : 68 : mp++;
327 : 68 : masklen = strtoul(mp, &cp, 10);
328 [ + - ][ + - ]: 68 : if (*mp == '\0' || *cp != '\0' || masklen > 128)
[ + - ]
329 : : return -1;
330 : : }
331 : :
332 [ + + ]: 175 : if (addr_pton(addrbuf, &tmp) == -1)
333 : : return -1;
334 : :
335 [ + + ]: 161 : if (mp == NULL)
336 : 93 : masklen = addr_unicast_masklen(tmp.af);
337 [ + - ]: 161 : if (masklen_valid(tmp.af, masklen) == -1)
338 : : return -2;
339 [ + - ]: 161 : if (addr_host_is_all0s(&tmp, masklen) != 0)
340 : : return -2;
341 : :
342 [ + - ]: 161 : if (n != NULL)
343 : : memcpy(n, &tmp, sizeof(*n));
344 [ + - ]: 161 : if (l != NULL)
345 : 161 : *l = masklen;
346 : :
347 : : return 0;
348 : : }
349 : :
350 : : static int
351 : 157 : addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
352 : : {
353 : : struct xaddr tmp_mask, tmp_result;
354 : :
355 [ + + ]: 157 : if (host->af != net->af)
356 : : return -1;
357 : :
358 [ + - ]: 85 : if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
359 : : return -1;
360 [ + - ]: 85 : if (addr_and(&tmp_result, host, &tmp_mask) == -1)
361 : : return -1;
362 : 85 : return addr_cmp(&tmp_result, net);
363 : : }
364 : :
365 : : /*
366 : : * Match "addr" against list pattern list "_list", which may contain a
367 : : * mix of CIDR addresses and old-school wildcards.
368 : : *
369 : : * If addr is NULL, then no matching is performed, but _list is parsed
370 : : * and checked for well-formedness.
371 : : *
372 : : * Returns 1 on match found (never returned when addr == NULL).
373 : : * Returns 0 on if no match found, or no errors found when addr == NULL.
374 : : * Returns -1 on negated match found (never returned when addr == NULL).
375 : : * Returns -2 on invalid list entry.
376 : : */
377 : : int
378 : 68 : addr_match_list(const char *addr, const char *_list)
379 : : {
380 : : char *list, *cp, *o;
381 : : struct xaddr try_addr, match_addr;
382 : : u_int masklen, neg;
383 : 68 : int ret = 0, r;
384 : :
385 [ + - ][ + + ]: 68 : if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
386 : 4 : debug2("%s: couldn't parse address %.100s", __func__, addr);
387 : 4 : return 0;
388 : : }
389 [ + - ]: 64 : if ((o = list = strdup(_list)) == NULL)
390 : : return -1;
391 [ + + ]: 232 : while ((cp = strsep(&list, ",")) != NULL) {
392 : 171 : neg = *cp == '!';
393 [ + + ]: 171 : if (neg)
394 : 32 : cp++;
395 [ + - ]: 171 : if (*cp == '\0') {
396 : : ret = -2;
397 : : break;
398 : : }
399 : : /* Prefer CIDR address matching */
400 : 171 : r = addr_pton_cidr(cp, &match_addr, &masklen);
401 [ - + ]: 171 : if (r == -2) {
402 : 0 : error("Inconsistent mask length for "
403 : : "network \"%.100s\"", cp);
404 : 0 : ret = -2;
405 : 0 : break;
406 [ + + ]: 171 : } else if (r == 0) {
407 [ + - ][ + + ]: 157 : if (addr != NULL && addr_netmatch(&try_addr,
408 : : &match_addr, masklen) == 0) {
409 : : foundit:
410 [ + + ]: 28 : if (neg) {
411 : : ret = -1;
412 : : break;
413 : : }
414 : : ret = 1;
415 : : }
416 : 154 : continue;
417 : : } else {
418 : : /* If CIDR parse failed, try wildcard string match */
419 [ + - ][ - + ]: 168 : if (addr != NULL && match_pattern(addr, cp) == 1)
420 : : goto foundit;
421 : : }
422 : : }
423 : 64 : free(o);
424 : :
425 : 64 : return ret;
426 : : }
427 : :
428 : : /*
429 : : * Match "addr" against list CIDR list "_list". Lexical wildcards and
430 : : * negation are not supported. If "addr" == NULL, will verify structure
431 : : * of "_list".
432 : : *
433 : : * Returns 1 on match found (never returned when addr == NULL).
434 : : * Returns 0 on if no match found, or no errors found when addr == NULL.
435 : : * Returns -1 on error
436 : : */
437 : : int
438 : 4 : addr_match_cidr_list(const char *addr, const char *_list)
439 : : {
440 : : char *list, *cp, *o;
441 : : struct xaddr try_addr, match_addr;
442 : : u_int masklen;
443 : 4 : int ret = 0, r;
444 : :
445 [ - + ][ # # ]: 4 : if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
446 : 0 : debug2("%s: couldn't parse address %.100s", __func__, addr);
447 : 0 : return 0;
448 : : }
449 [ + - ]: 4 : if ((o = list = strdup(_list)) == NULL)
450 : : return -1;
451 [ + + ]: 8 : while ((cp = strsep(&list, ",")) != NULL) {
452 [ - + ]: 4 : if (*cp == '\0') {
453 : 0 : error("%s: empty entry in list \"%.100s\"",
454 : : __func__, o);
455 : 0 : ret = -1;
456 : 0 : break;
457 : : }
458 : :
459 : : /*
460 : : * NB. This function is called in pre-auth with untrusted data,
461 : : * so be extra paranoid about junk reaching getaddrino (via
462 : : * addr_pton_cidr).
463 : : */
464 : :
465 : : /* Stop junk from reaching getaddrinfo. +3 is for masklen */
466 [ - + ]: 4 : if (strlen(cp) > INET6_ADDRSTRLEN + 3) {
467 : 0 : error("%s: list entry \"%.100s\" too long",
468 : : __func__, cp);
469 : 0 : ret = -1;
470 : 0 : break;
471 : : }
472 : : #define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/"
473 [ - + ]: 4 : if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) {
474 : 0 : error("%s: list entry \"%.100s\" contains invalid "
475 : : "characters", __func__, cp);
476 : 0 : ret = -1;
477 : : }
478 : :
479 : : /* Prefer CIDR address matching */
480 : 4 : r = addr_pton_cidr(cp, &match_addr, &masklen);
481 [ - + ]: 4 : if (r == -1) {
482 : 0 : error("Invalid network entry \"%.100s\"", cp);
483 : 0 : ret = -1;
484 : 0 : break;
485 [ - + ]: 4 : } else if (r == -2) {
486 : 0 : error("Inconsistent mask length for "
487 : : "network \"%.100s\"", cp);
488 : 0 : ret = -1;
489 : 0 : break;
490 [ - + ]: 4 : } else if (r == 0 && addr != NULL) {
491 [ # # ]: 0 : if (addr_netmatch(&try_addr, &match_addr,
492 : : masklen) == 0)
493 : 0 : ret = 1;
494 : 4 : continue;
495 : : }
496 : : }
497 : 4 : free(o);
498 : :
499 : 4 : return ret;
500 : : }
|