xref: /netbsd-src/crypto/external/bsd/openssh/dist/srclimit.c (revision ae87de8892f277bece3527c15b186ebcfa188227)
1 /*	$NetBSD: srclimit.c,v 1.3 2021/04/19 14:40:15 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2020 Darren Tucker <dtucker@openbsd.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 #include "includes.h"
19 __RCSID("$NetBSD: srclimit.c,v 1.3 2021/04/19 14:40:15 christos Exp $");
20 
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 
24 #include <limits.h>
25 #include <netdb.h>
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "addr.h"
30 #include "canohost.h"
31 #include "log.h"
32 #include "misc.h"
33 #include "srclimit.h"
34 #include "xmalloc.h"
35 
36 static int max_children, max_persource, ipv4_masklen, ipv6_masklen;
37 
38 /* Per connection state, used to enforce unauthenticated connection limit. */
39 static struct child_info {
40 	int id;
41 	struct xaddr addr;
42 } *child;
43 
44 void
45 srclimit_init(int max, int persource, int ipv4len, int ipv6len)
46 {
47 	int i;
48 
49 	max_children = max;
50 	ipv4_masklen = ipv4len;
51 	ipv6_masklen = ipv6len;
52 	max_persource = persource;
53 	if (max_persource == INT_MAX)	/* no limit */
54 		return;
55 	debug("%s: max connections %d, per source %d, masks %d,%d", __func__,
56 	    max, persource, ipv4len, ipv6len);
57 	if (max <= 0)
58 		fatal("%s: invalid number of sockets: %d", __func__, max);
59 	child = xcalloc(max_children, sizeof(*child));
60 	for (i = 0; i < max_children; i++)
61 		child[i].id = -1;
62 }
63 
64 /* returns 1 if connection allowed, 0 if not allowed. */
65 int
66 srclimit_check_allow(int sock, int id)
67 {
68 	struct xaddr xa, xb, xmask;
69 	struct sockaddr_storage addr;
70 	socklen_t addrlen = sizeof(addr);
71 	struct sockaddr *sa = (struct sockaddr *)&addr;
72 	int i, bits, first_unused, count = 0;
73 	char xas[NI_MAXHOST];
74 
75 	if (max_persource == INT_MAX)	/* no limit */
76 		return 1;
77 
78 	debug("%s: sock %d id %d limit %d", __func__, sock, id, max_persource);
79 	if (getpeername(sock, sa, &addrlen) != 0)
80 		return 1;	/* not remote socket? */
81 	if (addr_sa_to_xaddr(sa, addrlen, &xa) != 0)
82 		return 1;	/* unknown address family? */
83 
84 	/* Mask address off address to desired size. */
85 	bits = xa.af == AF_INET ? ipv4_masklen : ipv6_masklen;
86 	if (addr_netmask(xa.af, bits, &xmask) != 0 ||
87 	    addr_and(&xb, &xa, &xmask) != 0) {
88 		debug3("%s: invalid mask %d bits", __func__, bits);
89 		return 1;
90 	}
91 
92 	first_unused = max_children;
93 	/* Count matching entries and find first unused one. */
94 	for (i = 0; i < max_children; i++) {
95 		if (child[i].id == -1) {
96 			if (i < first_unused)
97 				first_unused = i;
98 		} else if (addr_cmp(&child[i].addr, &xb) == 0) {
99 			count++;
100 		}
101 	}
102 	if (addr_ntop(&xa, xas, sizeof(xas)) != 0) {
103 		debug3("%s: addr ntop failed", __func__);
104 		return 1;
105 	}
106 	debug3("%s: new unauthenticated connection from %s/%d, at %d of %d",
107 	    __func__, xas, bits, count, max_persource);
108 
109 	if (first_unused == max_children) { /* no free slot found */
110 		debug3("%s: no free slot", __func__);
111 		return 0;
112 	}
113 	if (first_unused < 0 || first_unused >= max_children)
114 		fatal("%s: internal error: first_unused out of range",
115 		    __func__);
116 
117 	if (count >= max_persource)
118 		return 0;
119 
120 	/* Connection allowed, store masked address. */
121 	child[first_unused].id = id;
122 	memcpy(&child[first_unused].addr, &xb, sizeof(xb));
123 	return 1;
124 }
125 
126 void
127 srclimit_done(int id)
128 {
129 	int i;
130 
131 	if (max_persource == INT_MAX)	/* no limit */
132 		return;
133 
134 	debug("%s: id %d", __func__, id);
135 	/* Clear corresponding state entry. */
136 	for (i = 0; i < max_children; i++) {
137 		if (child[i].id == id) {
138 			child[i].id = -1;
139 			return;
140 		}
141 	}
142 }
143