[BACK]Return to srclimit.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/srclimit.c, Revision 1.2

1.1       dtucker     1: /*
                      2:  * Copyright (c) 2020 Darren Tucker <dtucker@openbsd.org>
                      3:  *
                      4:  * Permission to use, copy, modify, and distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
                      7:  *
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16:
                     17: #include <sys/socket.h>
                     18: #include <sys/types.h>
                     19:
                     20: #include <limits.h>
                     21: #include <netdb.h>
                     22: #include <stdio.h>
                     23: #include <string.h>
                     24:
                     25: #include "addr.h"
                     26: #include "canohost.h"
                     27: #include "log.h"
                     28: #include "misc.h"
                     29: #include "srclimit.h"
                     30: #include "xmalloc.h"
                     31:
                     32: static int max_children, max_persource, ipv4_masklen, ipv6_masklen;
                     33:
                     34: /* Per connection state, used to enforce unauthenticated connection limit. */
                     35: static struct child_info {
                     36:        int id;
                     37:        struct xaddr addr;
                     38: } *child;
                     39:
                     40: void
                     41: srclimit_init(int max, int persource, int ipv4len, int ipv6len)
                     42: {
                     43:        int i;
                     44:
                     45:        max_children = max;
                     46:        ipv4_masklen = ipv4len;
                     47:        ipv6_masklen = ipv6len;
                     48:        max_persource = persource;
                     49:        if (max_persource == INT_MAX)   /* no limit */
                     50:                return;
                     51:        debug("%s: max connections %d, per source %d, masks %d,%d", __func__,
                     52:            max, persource, ipv4len, ipv6len);
                     53:        if (max <= 0)
                     54:                fatal("%s: invalid number of sockets: %d", __func__, max);
                     55:        child = xcalloc(max_children, sizeof(*child));
                     56:        for (i = 0; i < max_children; i++)
                     57:                child[i].id = -1;
                     58: }
                     59:
                     60: /* returns 1 if connection allowed, 0 if not allowed. */
                     61: int
                     62: srclimit_check_allow(int sock, int id)
                     63: {
                     64:        struct xaddr xa, xb, xmask;
                     65:        struct sockaddr_storage addr;
                     66:        socklen_t addrlen = sizeof(addr);
                     67:        struct sockaddr *sa = (struct sockaddr *)&addr;
                     68:        int i, bits, first_unused, count = 0;
                     69:        char xas[NI_MAXHOST];
                     70:
                     71:        if (max_persource == INT_MAX)   /* no limit */
                     72:                return 1;
                     73:
                     74:        debug("%s: sock %d id %d limit %d", __func__, sock, id, max_persource);
                     75:        if (getpeername(sock, sa, &addrlen) != 0)
                     76:                return 1;       /* not remote socket? */
                     77:        if (addr_sa_to_xaddr(sa, addrlen, &xa) != 0)
                     78:                return 1;       /* unknown address family? */
                     79:
                     80:        /* Mask address off address to desired size. */
                     81:        bits = xa.af == AF_INET ? ipv4_masklen : ipv6_masklen;
                     82:        if (addr_netmask(xa.af, bits, &xmask) != 0 ||
                     83:            addr_and(&xb, &xa, &xmask) != 0) {
                     84:                debug3("%s: invalid mask %d bits", __func__, bits);
                     85:                return 1;
                     86:        }
                     87:
                     88:        first_unused = max_children;
                     89:        /* Count matching entries and find first unused one. */
                     90:        for (i = 0; i < max_children; i++) {
                     91:                if (child[i].id == -1) {
                     92:                        if (i < first_unused)
                     93:                                first_unused = i;
                     94:                } else if (addr_cmp(&child[i].addr, &xb) == 0) {
                     95:                        count++;
                     96:                }
                     97:        }
                     98:        if (addr_ntop(&xa, xas, sizeof(xas)) != 0) {
                     99:                debug3("%s: addr ntop failed", __func__);
                    100:                return 1;
                    101:        }
                    102:        debug3("%s: new unauthenticated connection from %s/%d, at %d of %d",
1.2     ! djm       103:            __func__, xas, bits, count, max_persource);
1.1       dtucker   104:
                    105:        if (first_unused == max_children) { /* no free slot found */
                    106:                debug3("%s: no free slot", __func__);
                    107:                return 0;
                    108:        }
                    109:        if (first_unused < 0 || first_unused >= max_children)
                    110:                fatal("%s: internal error: first_unused out of range",
                    111:                    __func__);
                    112:
                    113:        if (count >= max_persource)
                    114:                return 0;
                    115:
                    116:        /* Connection allowed, store masked address. */
                    117:        child[first_unused].id = id;
                    118:        memcpy(&child[first_unused].addr, &xb, sizeof(xb));
                    119:        return 1;
                    120: }
                    121:
                    122: void
                    123: srclimit_done(int id)
                    124: {
                    125:        int i;
                    126:
                    127:        if (max_persource == INT_MAX)   /* no limit */
                    128:                return;
                    129:
                    130:        debug("%s: id %d", __func__, id);
                    131:        /* Clear corresponding state entry. */
                    132:        for (i = 0; i < max_children; i++) {
                    133:                if (child[i].id == id) {
                    134:                        child[i].id = -1;
                    135:                        return;
                    136:                }
                    137:        }
                    138: }