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: }