[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.1

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",
        !           103:             __func__, xas, bits, count, max_persource);
        !           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: }