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