1 /*
2 * Copyright (c) 2020 Darren Tucker <dtucker@openbsd.org>
3 * Copyright (c) 2024 Damien Miller <djm@mindrot.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include "includes.h"
19
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 #include <openbsd-compat/sys-tree.h>
23
24 #include <limits.h>
25 #include <netdb.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "addr.h"
31 #include "canohost.h"
32 #include "log.h"
33 #include "misc.h"
34 #include "srclimit.h"
35 #include "xmalloc.h"
36 #include "servconf.h"
37 #include "match.h"
38
39 static int max_children, max_persource, ipv4_masklen, ipv6_masklen;
40 static struct per_source_penalty penalty_cfg;
41 static char *penalty_exempt;
42
43 /* Per connection state, used to enforce unauthenticated connection limit. */
44 static struct child_info {
45 int id;
46 struct xaddr addr;
47 } *children;
48
49 /*
50 * Penalised addresses, active entries here prohibit connections until expired.
51 * Entries become active when more than penalty_min seconds of penalty are
52 * outstanding.
53 */
54 struct penalty {
55 struct xaddr addr;
56 time_t expiry;
57 int active;
58 const char *reason;
59 RB_ENTRY(penalty) by_addr;
60 RB_ENTRY(penalty) by_expiry;
61 };
62 static int penalty_addr_cmp(struct penalty *a, struct penalty *b);
63 static int penalty_expiry_cmp(struct penalty *a, struct penalty *b);
64 RB_HEAD(penalties_by_addr, penalty) penalties_by_addr4, penalties_by_addr6;
65 RB_HEAD(penalties_by_expiry, penalty) penalties_by_expiry4, penalties_by_expiry6;
66 RB_GENERATE_STATIC(penalties_by_addr, penalty, by_addr, penalty_addr_cmp)
67 RB_GENERATE_STATIC(penalties_by_expiry, penalty, by_expiry, penalty_expiry_cmp)
68 static size_t npenalties4, npenalties6;
69
70 static int
srclimit_mask_addr(const struct xaddr * addr,int bits,struct xaddr * masked)71 srclimit_mask_addr(const struct xaddr *addr, int bits, struct xaddr *masked)
72 {
73 struct xaddr xmask;
74
75 /* Mask address off address to desired size. */
76 if (addr_netmask(addr->af, bits, &xmask) != 0 ||
77 addr_and(masked, addr, &xmask) != 0) {
78 debug3_f("%s: invalid mask %d bits", __func__, bits);
79 return -1;
80 }
81 return 0;
82 }
83
84 static int
srclimit_peer_addr(int sock,struct xaddr * addr)85 srclimit_peer_addr(int sock, struct xaddr *addr)
86 {
87 struct sockaddr_storage storage;
88 socklen_t addrlen = sizeof(storage);
89 struct sockaddr *sa = (struct sockaddr *)&storage;
90
91 if (getpeername(sock, sa, &addrlen) != 0)
92 return 1; /* not remote socket? */
93 if (addr_sa_to_xaddr(sa, addrlen, addr) != 0)
94 return 1; /* unknown address family? */
95 return 0;
96 }
97
98 void
srclimit_init(int max,int persource,int ipv4len,int ipv6len,struct per_source_penalty * penalty_conf,const char * penalty_exempt_conf)99 srclimit_init(int max, int persource, int ipv4len, int ipv6len,
100 struct per_source_penalty *penalty_conf, const char *penalty_exempt_conf)
101 {
102 int i;
103
104 max_children = max;
105 ipv4_masklen = ipv4len;
106 ipv6_masklen = ipv6len;
107 max_persource = persource;
108 penalty_cfg = *penalty_conf;
109 if (penalty_cfg.max_sources4 < 0 || penalty_cfg.max_sources6 < 0)
110 fatal_f("invalid max_sources"); /* shouldn't happen */
111 penalty_exempt = penalty_exempt_conf == NULL ?
112 NULL : xstrdup(penalty_exempt_conf);
113 RB_INIT(&penalties_by_addr4);
114 RB_INIT(&penalties_by_expiry4);
115 RB_INIT(&penalties_by_addr6);
116 RB_INIT(&penalties_by_expiry6);
117 if (max_persource == INT_MAX) /* no limit */
118 return;
119 debug("%s: max connections %d, per source %d, masks %d,%d", __func__,
120 max, persource, ipv4len, ipv6len);
121 if (max <= 0)
122 fatal("%s: invalid number of sockets: %d", __func__, max);
123 children = xcalloc(max_children, sizeof(*children));
124 for (i = 0; i < max_children; i++)
125 children[i].id = -1;
126 }
127
128 /* returns 1 if connection allowed, 0 if not allowed. */
129 int
srclimit_check_allow(int sock,int id)130 srclimit_check_allow(int sock, int id)
131 {
132 struct xaddr xa, xb;
133 int i, bits, first_unused, count = 0;
134 char xas[NI_MAXHOST];
135
136 if (max_persource == INT_MAX) /* no limit */
137 return 1;
138
139 debug("%s: sock %d id %d limit %d", __func__, sock, id, max_persource);
140 if (srclimit_peer_addr(sock, &xa) != 0)
141 return 1;
142 bits = xa.af == AF_INET ? ipv4_masklen : ipv6_masklen;
143 if (srclimit_mask_addr(&xa, bits, &xb) != 0)
144 return 1;
145
146 first_unused = max_children;
147 /* Count matching entries and find first unused one. */
148 for (i = 0; i < max_children; i++) {
149 if (children[i].id == -1) {
150 if (i < first_unused)
151 first_unused = i;
152 } else if (addr_cmp(&children[i].addr, &xb) == 0) {
153 count++;
154 }
155 }
156 if (addr_ntop(&xa, xas, sizeof(xas)) != 0) {
157 debug3("%s: addr ntop failed", __func__);
158 return 1;
159 }
160 debug3("%s: new unauthenticated connection from %s/%d, at %d of %d",
161 __func__, xas, bits, count, max_persource);
162
163 if (first_unused == max_children) { /* no free slot found */
164 debug3("%s: no free slot", __func__);
165 return 0;
166 }
167 if (first_unused < 0 || first_unused >= max_children)
168 fatal("%s: internal error: first_unused out of range",
169 __func__);
170
171 if (count >= max_persource)
172 return 0;
173
174 /* Connection allowed, store masked address. */
175 children[first_unused].id = id;
176 memcpy(&children[first_unused].addr, &xb, sizeof(xb));
177 return 1;
178 }
179
180 void
srclimit_done(int id)181 srclimit_done(int id)
182 {
183 int i;
184
185 if (max_persource == INT_MAX) /* no limit */
186 return;
187
188 debug("%s: id %d", __func__, id);
189 /* Clear corresponding state entry. */
190 for (i = 0; i < max_children; i++) {
191 if (children[i].id == id) {
192 children[i].id = -1;
193 return;
194 }
195 }
196 }
197
198 static int
penalty_addr_cmp(struct penalty * a,struct penalty * b)199 penalty_addr_cmp(struct penalty *a, struct penalty *b)
200 {
201 return addr_cmp(&a->addr, &b->addr);
202 /* Addresses must be unique in by_addr, so no need to tiebreak */
203 }
204
205 static int
penalty_expiry_cmp(struct penalty * a,struct penalty * b)206 penalty_expiry_cmp(struct penalty *a, struct penalty *b)
207 {
208 if (a->expiry != b->expiry)
209 return a->expiry < b->expiry ? -1 : 1;
210 /* Tiebreak on addresses */
211 return addr_cmp(&a->addr, &b->addr);
212 }
213
214 static void
expire_penalties_from_tree(time_t now,const char * t,struct penalties_by_expiry * by_expiry,struct penalties_by_addr * by_addr,size_t * npenaltiesp)215 expire_penalties_from_tree(time_t now, const char *t,
216 struct penalties_by_expiry *by_expiry,
217 struct penalties_by_addr *by_addr, size_t *npenaltiesp)
218 {
219 struct penalty *penalty, *tmp;
220
221 /* XXX avoid full scan of tree, e.g. min-heap */
222 RB_FOREACH_SAFE(penalty, penalties_by_expiry, by_expiry, tmp) {
223 if (penalty->expiry >= now)
224 break;
225 if (RB_REMOVE(penalties_by_expiry, by_expiry,
226 penalty) != penalty ||
227 RB_REMOVE(penalties_by_addr, by_addr,
228 penalty) != penalty)
229 fatal_f("internal error: %s penalty table corrupt", t);
230 free(penalty);
231 if ((*npenaltiesp)-- == 0)
232 fatal_f("internal error: %s npenalties underflow", t);
233 }
234 }
235
236 static void
expire_penalties(time_t now)237 expire_penalties(time_t now)
238 {
239 expire_penalties_from_tree(now, "ipv4",
240 &penalties_by_expiry4, &penalties_by_addr4, &npenalties4);
241 expire_penalties_from_tree(now, "ipv6",
242 &penalties_by_expiry6, &penalties_by_addr6, &npenalties6);
243 }
244
245 static void
addr_masklen_ntop(struct xaddr * addr,int masklen,char * s,size_t slen)246 addr_masklen_ntop(struct xaddr *addr, int masklen, char *s, size_t slen)
247 {
248 size_t o;
249
250 if (addr_ntop(addr, s, slen) != 0) {
251 strlcpy(s, "UNKNOWN", slen);
252 return;
253 }
254 if ((o = strlen(s)) < slen)
255 snprintf(s + o, slen - o, "/%d", masklen);
256 }
257
258 int
srclimit_penalty_check_allow(int sock,const char ** reason)259 srclimit_penalty_check_allow(int sock, const char **reason)
260 {
261 struct xaddr addr;
262 struct penalty find, *penalty;
263 time_t now;
264 int bits, max_sources, overflow_mode;
265 char addr_s[NI_MAXHOST];
266 struct penalties_by_addr *by_addr;
267 size_t npenalties;
268
269 if (!penalty_cfg.enabled)
270 return 1;
271 if (srclimit_peer_addr(sock, &addr) != 0)
272 return 1;
273 if (penalty_exempt != NULL) {
274 if (addr_ntop(&addr, addr_s, sizeof(addr_s)) != 0)
275 return 1; /* shouldn't happen */
276 if (addr_match_list(addr_s, penalty_exempt) == 1) {
277 return 1;
278 }
279 }
280 now = monotime();
281 expire_penalties(now);
282 by_addr = addr.af == AF_INET ?
283 &penalties_by_addr4 : &penalties_by_addr6;
284 max_sources = addr.af == AF_INET ?
285 penalty_cfg.max_sources4 : penalty_cfg.max_sources6;
286 overflow_mode = addr.af == AF_INET ?
287 penalty_cfg.overflow_mode : penalty_cfg.overflow_mode6;
288 npenalties = addr.af == AF_INET ? npenalties4 : npenalties6;
289 if (npenalties >= (size_t)max_sources &&
290 overflow_mode == PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL) {
291 *reason = "too many penalised addresses";
292 return 0;
293 }
294 bits = addr.af == AF_INET ? ipv4_masklen : ipv6_masklen;
295 memset(&find, 0, sizeof(find));
296 if (srclimit_mask_addr(&addr, bits, &find.addr) != 0)
297 return 1;
298 if ((penalty = RB_FIND(penalties_by_addr, by_addr, &find)) == NULL)
299 return 1; /* no penalty */
300 if (penalty->expiry < now) {
301 expire_penalties(now);
302 return 1; /* expired penalty */
303 }
304 if (!penalty->active)
305 return 1; /* Penalty hasn't hit activation threshold yet */
306 *reason = penalty->reason;
307 return 0;
308 }
309
310 static void
srclimit_early_expire_penalties_from_tree(const char * t,struct penalties_by_expiry * by_expiry,struct penalties_by_addr * by_addr,size_t * npenaltiesp,size_t max_sources)311 srclimit_early_expire_penalties_from_tree(const char *t,
312 struct penalties_by_expiry *by_expiry,
313 struct penalties_by_addr *by_addr, size_t *npenaltiesp, size_t max_sources)
314 {
315 struct penalty *p = NULL;
316 int bits;
317 char s[NI_MAXHOST + 4];
318
319 /* Delete the soonest-to-expire penalties. */
320 while (*npenaltiesp > max_sources) {
321 if ((p = RB_MIN(penalties_by_expiry, by_expiry)) == NULL)
322 fatal_f("internal error: %s table corrupt (find)", t);
323 bits = p->addr.af == AF_INET ? ipv4_masklen : ipv6_masklen;
324 addr_masklen_ntop(&p->addr, bits, s, sizeof(s));
325 debug3_f("%s overflow, remove %s", t, s);
326 if (RB_REMOVE(penalties_by_expiry, by_expiry, p) != p ||
327 RB_REMOVE(penalties_by_addr, by_addr, p) != p)
328 fatal_f("internal error: %s table corrupt (remove)", t);
329 free(p);
330 (*npenaltiesp)--;
331 }
332 }
333
334 static void
srclimit_early_expire_penalties(void)335 srclimit_early_expire_penalties(void)
336 {
337 srclimit_early_expire_penalties_from_tree("ipv4",
338 &penalties_by_expiry4, &penalties_by_addr4, &npenalties4,
339 (size_t)penalty_cfg.max_sources4);
340 srclimit_early_expire_penalties_from_tree("ipv6",
341 &penalties_by_expiry6, &penalties_by_addr6, &npenalties6,
342 (size_t)penalty_cfg.max_sources6);
343 }
344
345 void
srclimit_penalise(struct xaddr * addr,int penalty_type)346 srclimit_penalise(struct xaddr *addr, int penalty_type)
347 {
348 struct xaddr masked;
349 struct penalty *penalty = NULL, *existing = NULL;
350 time_t now;
351 int bits, penalty_secs, max_sources = 0, overflow_mode;
352 char addrnetmask[NI_MAXHOST + 4];
353 const char *reason = NULL, *t;
354 size_t *npenaltiesp = NULL;
355 struct penalties_by_addr *by_addr = NULL;
356 struct penalties_by_expiry *by_expiry = NULL;
357
358 if (!penalty_cfg.enabled)
359 return;
360 if (penalty_exempt != NULL) {
361 if (addr_ntop(addr, addrnetmask, sizeof(addrnetmask)) != 0)
362 return; /* shouldn't happen */
363 if (addr_match_list(addrnetmask, penalty_exempt) == 1) {
364 debug3_f("address %s is exempt", addrnetmask);
365 return;
366 }
367 }
368
369 switch (penalty_type) {
370 case SRCLIMIT_PENALTY_NONE:
371 return;
372 case SRCLIMIT_PENALTY_CRASH:
373 penalty_secs = penalty_cfg.penalty_crash;
374 reason = "penalty: caused crash";
375 break;
376 case SRCLIMIT_PENALTY_AUTHFAIL:
377 penalty_secs = penalty_cfg.penalty_authfail;
378 reason = "penalty: failed authentication";
379 break;
380 case SRCLIMIT_PENALTY_NOAUTH:
381 penalty_secs = penalty_cfg.penalty_noauth;
382 reason = "penalty: connections without attempting authentication";
383 break;
384 case SRCLIMIT_PENALTY_REFUSECONNECTION:
385 penalty_secs = penalty_cfg.penalty_refuseconnection;
386 reason = "penalty: connection prohibited by RefuseConnection";
387 break;
388 case SRCLIMIT_PENALTY_GRACE_EXCEEDED:
389 penalty_secs = penalty_cfg.penalty_crash;
390 reason = "penalty: exceeded LoginGraceTime";
391 break;
392 default:
393 fatal_f("internal error: unknown penalty %d", penalty_type);
394 }
395 bits = addr->af == AF_INET ? ipv4_masklen : ipv6_masklen;
396 if (srclimit_mask_addr(addr, bits, &masked) != 0)
397 return;
398 addr_masklen_ntop(addr, bits, addrnetmask, sizeof(addrnetmask));
399
400 now = monotime();
401 expire_penalties(now);
402 by_expiry = addr->af == AF_INET ?
403 &penalties_by_expiry4 : &penalties_by_expiry6;
404 by_addr = addr->af == AF_INET ?
405 &penalties_by_addr4 : &penalties_by_addr6;
406 max_sources = addr->af == AF_INET ?
407 penalty_cfg.max_sources4 : penalty_cfg.max_sources6;
408 overflow_mode = addr->af == AF_INET ?
409 penalty_cfg.overflow_mode : penalty_cfg.overflow_mode6;
410 npenaltiesp = addr->af == AF_INET ? &npenalties4 : &npenalties6;
411 t = addr->af == AF_INET ? "ipv4" : "ipv6";
412 if (*npenaltiesp >= (size_t)max_sources &&
413 overflow_mode == PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL) {
414 verbose_f("%s penalty table full, cannot penalise %s for %s", t,
415 addrnetmask, reason);
416 return;
417 }
418
419 penalty = xcalloc(1, sizeof(*penalty));
420 penalty->addr = masked;
421 penalty->expiry = now + penalty_secs;
422 penalty->reason = reason;
423 if ((existing = RB_INSERT(penalties_by_addr, by_addr,
424 penalty)) == NULL) {
425 /* penalty didn't previously exist */
426 if (penalty_secs > penalty_cfg.penalty_min)
427 penalty->active = 1;
428 if (RB_INSERT(penalties_by_expiry, by_expiry, penalty) != NULL)
429 fatal_f("internal error: %s penalty tables corrupt", t);
430 verbose_f("%s: new %s %s penalty of %d seconds for %s", t,
431 addrnetmask, penalty->active ? "active" : "deferred",
432 penalty_secs, reason);
433 if (++(*npenaltiesp) > (size_t)max_sources)
434 srclimit_early_expire_penalties(); /* permissive */
435 return;
436 }
437 debug_f("%s penalty for %s %s already exists, %lld seconds remaining",
438 existing->active ? "active" : "inactive", t,
439 addrnetmask, (long long)(existing->expiry - now));
440 /* Expiry information is about to change, remove from tree */
441 if (RB_REMOVE(penalties_by_expiry, by_expiry, existing) != existing)
442 fatal_f("internal error: %s penalty table corrupt (remove)", t);
443 /* An entry already existed. Accumulate penalty up to maximum */
444 existing->expiry += penalty_secs;
445 if (existing->expiry - now > penalty_cfg.penalty_max)
446 existing->expiry = now + penalty_cfg.penalty_max;
447 if (existing->expiry - now > penalty_cfg.penalty_min &&
448 !existing->active) {
449 verbose_f("%s: activating %s penalty of %lld seconds for %s",
450 addrnetmask, t, (long long)(existing->expiry - now),
451 reason);
452 existing->active = 1;
453 }
454 existing->reason = penalty->reason;
455 free(penalty);
456 penalty = NULL;
457 /* Re-insert into expiry tree */
458 if (RB_INSERT(penalties_by_expiry, by_expiry, existing) != NULL)
459 fatal_f("internal error: %s penalty table corrupt (insert)", t);
460 }
461
462 static void
srclimit_penalty_info_for_tree(const char * t,struct penalties_by_expiry * by_expiry,size_t npenalties)463 srclimit_penalty_info_for_tree(const char *t,
464 struct penalties_by_expiry *by_expiry, size_t npenalties)
465 {
466 struct penalty *p = NULL;
467 int bits;
468 char s[NI_MAXHOST + 4];
469 time_t now;
470
471 now = monotime();
472 logit("%zu active %s penalties", npenalties, t);
473 RB_FOREACH(p, penalties_by_expiry, by_expiry) {
474 bits = p->addr.af == AF_INET ? ipv4_masklen : ipv6_masklen;
475 addr_masklen_ntop(&p->addr, bits, s, sizeof(s));
476 if (p->expiry < now)
477 logit("client %s %s (expired)", s, p->reason);
478 else {
479 logit("client %s %s (%llu secs left)", s, p->reason,
480 (long long)(p->expiry - now));
481 }
482 }
483 }
484
485 void
srclimit_penalty_info(void)486 srclimit_penalty_info(void)
487 {
488 srclimit_penalty_info_for_tree("ipv4",
489 &penalties_by_expiry4, npenalties4);
490 srclimit_penalty_info_for_tree("ipv6",
491 &penalties_by_expiry6, npenalties6);
492 }
493