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