Annotation of src/usr.bin/ssh/addrmatch.c, Revision 1.13
1.13 ! djm 1: /* $OpenBSD: addrmatch.c,v 1.12 2016/08/23 08:17: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: {
204: struct addrinfo hints, *ai;
205:
206: memset(&hints, '\0', sizeof(hints));
207: hints.ai_flags = AI_NUMERICHOST;
208:
209: if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
210: return -1;
211:
212: if (ai == NULL || ai->ai_addr == NULL)
213: return -1;
214:
215: if (n != NULL &&
216: addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) {
217: freeaddrinfo(ai);
218: return -1;
219: }
220:
221: freeaddrinfo(ai);
222: return 0;
223: }
224:
225: /*
226: * Perform bitwise negation of address
227: * Returns 0 on success, -1 on failure.
228: */
229: static int
230: addr_invert(struct xaddr *n)
231: {
232: int i;
233:
234: if (n == NULL)
235: return (-1);
236:
237: switch (n->af) {
238: case AF_INET:
239: n->v4.s_addr = ~n->v4.s_addr;
240: return (0);
241: case AF_INET6:
242: for (i = 0; i < 4; i++)
243: n->addr32[i] = ~n->addr32[i];
244: return (0);
245: default:
246: return (-1);
247: }
248: }
249:
250: /*
251: * Calculate a netmask of length 'l' for address family 'af' and
252: * store it in 'n'.
253: * Returns 0 on success, -1 on failure.
254: */
255: static int
256: addr_hostmask(int af, u_int l, struct xaddr *n)
257: {
258: if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
259: return (-1);
260: return (0);
261: }
262:
263: /*
264: * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::)
265: * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure.
266: */
267: static int
268: addr_is_all0s(const struct xaddr *a)
269: {
270: int i;
271:
272: switch (a->af) {
273: case AF_INET:
274: return (a->v4.s_addr == 0 ? 0 : -1);
275: case AF_INET6:;
276: for (i = 0; i < 4; i++)
277: if (a->addr32[i] != 0)
278: return (-1);
279: return (0);
280: default:
281: return (-1);
282: }
283: }
284:
285: /*
286: * Test whether host portion of address 'a', as determined by 'masklen'
287: * is all zeros.
288: * Returns 0 on if host portion of address is all-zeros,
289: * -1 if not all zeros or on failure.
290: */
291: static int
292: addr_host_is_all0s(const struct xaddr *a, u_int masklen)
293: {
294: struct xaddr tmp_addr, tmp_mask, tmp_result;
295:
296: memcpy(&tmp_addr, a, sizeof(tmp_addr));
297: if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
298: return (-1);
299: if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
300: return (-1);
301: return (addr_is_all0s(&tmp_result));
302: }
303:
304: /*
305: * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
306: * Return -1 on parse error, -2 on inconsistency or 0 on success.
307: */
308: static int
309: addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
310: {
311: struct xaddr tmp;
312: long unsigned int masklen = 999;
313: char addrbuf[64], *mp, *cp;
314:
315: /* Don't modify argument */
1.6 dtucker 316: if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) >= sizeof(addrbuf))
1.1 djm 317: return -1;
318:
319: if ((mp = strchr(addrbuf, '/')) != NULL) {
320: *mp = '\0';
321: mp++;
322: masklen = strtoul(mp, &cp, 10);
323: if (*mp == '\0' || *cp != '\0' || masklen > 128)
324: return -1;
325: }
326:
327: if (addr_pton(addrbuf, &tmp) == -1)
328: return -1;
329:
330: if (mp == NULL)
331: masklen = addr_unicast_masklen(tmp.af);
332: if (masklen_valid(tmp.af, masklen) == -1)
333: return -2;
334: if (addr_host_is_all0s(&tmp, masklen) != 0)
335: return -2;
336:
337: if (n != NULL)
338: memcpy(n, &tmp, sizeof(*n));
339: if (l != NULL)
340: *l = masklen;
341:
342: return 0;
343: }
344:
345: static int
346: addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
347: {
348: struct xaddr tmp_mask, tmp_result;
349:
350: if (host->af != net->af)
351: return -1;
352:
353: if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
354: return -1;
355: if (addr_and(&tmp_result, host, &tmp_mask) == -1)
356: return -1;
357: return addr_cmp(&tmp_result, net);
358: }
359:
360: /*
361: * Match "addr" against list pattern list "_list", which may contain a
362: * mix of CIDR addresses and old-school wildcards.
363: *
364: * If addr is NULL, then no matching is performed, but _list is parsed
365: * and checked for well-formedness.
366: *
367: * Returns 1 on match found (never returned when addr == NULL).
368: * Returns 0 on if no match found, or no errors found when addr == NULL.
1.3 djm 369: * Returns -1 on negated match found (never returned when addr == NULL).
370: * Returns -2 on invalid list entry.
1.1 djm 371: */
372: int
373: addr_match_list(const char *addr, const char *_list)
374: {
375: char *list, *cp, *o;
376: struct xaddr try_addr, match_addr;
377: u_int masklen, neg;
378: int ret = 0, r;
379:
1.2 djm 380: if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
381: debug2("%s: couldn't parse address %.100s", __func__, addr);
382: return 0;
383: }
1.1 djm 384: if ((o = list = strdup(_list)) == NULL)
385: return -1;
386: while ((cp = strsep(&list, ",")) != NULL) {
387: neg = *cp == '!';
388: if (neg)
389: cp++;
390: if (*cp == '\0') {
1.3 djm 391: ret = -2;
1.1 djm 392: break;
393: }
394: /* Prefer CIDR address matching */
395: r = addr_pton_cidr(cp, &match_addr, &masklen);
396: if (r == -2) {
1.12 djm 397: debug2("%s: inconsistent mask length for "
398: "match network \"%.100s\"", __func__, cp);
1.3 djm 399: ret = -2;
1.1 djm 400: break;
401: } else if (r == 0) {
402: if (addr != NULL && addr_netmatch(&try_addr,
403: &match_addr, masklen) == 0) {
404: foundit:
405: if (neg) {
1.3 djm 406: ret = -1;
1.1 djm 407: break;
408: }
409: ret = 1;
1.13 ! djm 410: }
1.1 djm 411: continue;
412: } else {
413: /* If CIDR parse failed, try wildcard string match */
414: if (addr != NULL && match_pattern(addr, cp) == 1)
415: goto foundit;
1.5 djm 416: }
417: }
1.7 djm 418: free(o);
1.5 djm 419:
420: return ret;
421: }
422:
423: /*
424: * Match "addr" against list CIDR list "_list". Lexical wildcards and
425: * negation are not supported. If "addr" == NULL, will verify structure
426: * of "_list".
427: *
428: * Returns 1 on match found (never returned when addr == NULL).
429: * Returns 0 on if no match found, or no errors found when addr == NULL.
430: * Returns -1 on error
431: */
432: int
433: addr_match_cidr_list(const char *addr, const char *_list)
434: {
435: char *list, *cp, *o;
436: struct xaddr try_addr, match_addr;
437: u_int masklen;
438: int ret = 0, r;
439:
440: if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
441: debug2("%s: couldn't parse address %.100s", __func__, addr);
442: return 0;
443: }
444: if ((o = list = strdup(_list)) == NULL)
445: return -1;
446: while ((cp = strsep(&list, ",")) != NULL) {
447: if (*cp == '\0') {
448: error("%s: empty entry in list \"%.100s\"",
449: __func__, o);
450: ret = -1;
451: break;
452: }
453:
454: /*
455: * NB. This function is called in pre-auth with untrusted data,
456: * so be extra paranoid about junk reaching getaddrino (via
457: * addr_pton_cidr).
458: */
459:
460: /* Stop junk from reaching getaddrinfo. +3 is for masklen */
461: if (strlen(cp) > INET6_ADDRSTRLEN + 3) {
462: error("%s: list entry \"%.100s\" too long",
463: __func__, cp);
464: ret = -1;
465: break;
466: }
467: #define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/"
468: if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) {
469: error("%s: list entry \"%.100s\" contains invalid "
470: "characters", __func__, cp);
471: ret = -1;
472: }
473:
474: /* Prefer CIDR address matching */
475: r = addr_pton_cidr(cp, &match_addr, &masklen);
476: if (r == -1) {
477: error("Invalid network entry \"%.100s\"", cp);
478: ret = -1;
479: break;
480: } else if (r == -2) {
481: error("Inconsistent mask length for "
482: "network \"%.100s\"", cp);
483: ret = -1;
484: break;
485: } else if (r == 0 && addr != NULL) {
486: if (addr_netmatch(&try_addr, &match_addr,
487: masklen) == 0)
488: ret = 1;
489: continue;
1.1 djm 490: }
491: }
1.7 djm 492: free(o);
1.1 djm 493:
494: return ret;
495: }