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 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 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 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 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 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 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 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 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 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 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 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 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 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 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_GRACE_EXCEEDED: 385 penalty_secs = penalty_cfg.penalty_crash; 386 reason = "penalty: exceeded LoginGraceTime"; 387 break; 388 default: 389 fatal_f("internal error: unknown penalty %d", penalty_type); 390 } 391 bits = addr->af == AF_INET ? ipv4_masklen : ipv6_masklen; 392 if (srclimit_mask_addr(addr, bits, &masked) != 0) 393 return; 394 addr_masklen_ntop(addr, bits, addrnetmask, sizeof(addrnetmask)); 395 396 now = monotime(); 397 expire_penalties(now); 398 by_expiry = addr->af == AF_INET ? 399 &penalties_by_expiry4 : &penalties_by_expiry6; 400 by_addr = addr->af == AF_INET ? 401 &penalties_by_addr4 : &penalties_by_addr6; 402 max_sources = addr->af == AF_INET ? 403 penalty_cfg.max_sources4 : penalty_cfg.max_sources6; 404 overflow_mode = addr->af == AF_INET ? 405 penalty_cfg.overflow_mode : penalty_cfg.overflow_mode6; 406 npenaltiesp = addr->af == AF_INET ? &npenalties4 : &npenalties6; 407 t = addr->af == AF_INET ? "ipv4" : "ipv6"; 408 if (*npenaltiesp >= (size_t)max_sources && 409 overflow_mode == PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL) { 410 verbose_f("%s penalty table full, cannot penalise %s for %s", t, 411 addrnetmask, reason); 412 return; 413 } 414 415 penalty = xcalloc(1, sizeof(*penalty)); 416 penalty->addr = masked; 417 penalty->expiry = now + penalty_secs; 418 penalty->reason = reason; 419 if ((existing = RB_INSERT(penalties_by_addr, by_addr, 420 penalty)) == NULL) { 421 /* penalty didn't previously exist */ 422 if (penalty_secs > penalty_cfg.penalty_min) 423 penalty->active = 1; 424 if (RB_INSERT(penalties_by_expiry, by_expiry, penalty) != NULL) 425 fatal_f("internal error: %s penalty tables corrupt", t); 426 verbose_f("%s: new %s %s penalty of %d seconds for %s", t, 427 addrnetmask, penalty->active ? "active" : "deferred", 428 penalty_secs, reason); 429 if (++(*npenaltiesp) > (size_t)max_sources) 430 srclimit_early_expire_penalties(); /* permissive */ 431 return; 432 } 433 debug_f("%s penalty for %s %s already exists, %lld seconds remaining", 434 existing->active ? "active" : "inactive", t, 435 addrnetmask, (long long)(existing->expiry - now)); 436 /* Expiry information is about to change, remove from tree */ 437 if (RB_REMOVE(penalties_by_expiry, by_expiry, existing) != existing) 438 fatal_f("internal error: %s penalty table corrupt (remove)", t); 439 /* An entry already existed. Accumulate penalty up to maximum */ 440 existing->expiry += penalty_secs; 441 if (existing->expiry - now > penalty_cfg.penalty_max) 442 existing->expiry = now + penalty_cfg.penalty_max; 443 if (existing->expiry - now > penalty_cfg.penalty_min && 444 !existing->active) { 445 verbose_f("%s: activating %s penalty of %lld seconds for %s", 446 addrnetmask, t, (long long)(existing->expiry - now), 447 reason); 448 existing->active = 1; 449 } 450 existing->reason = penalty->reason; 451 free(penalty); 452 penalty = NULL; 453 /* Re-insert into expiry tree */ 454 if (RB_INSERT(penalties_by_expiry, by_expiry, existing) != NULL) 455 fatal_f("internal error: %s penalty table corrupt (insert)", t); 456 } 457 458 static void 459 srclimit_penalty_info_for_tree(const char *t, 460 struct penalties_by_expiry *by_expiry, size_t npenalties) 461 { 462 struct penalty *p = NULL; 463 int bits; 464 char s[NI_MAXHOST + 4]; 465 time_t now; 466 467 now = monotime(); 468 logit("%zu active %s penalties", npenalties, t); 469 RB_FOREACH(p, penalties_by_expiry, by_expiry) { 470 bits = p->addr.af == AF_INET ? ipv4_masklen : ipv6_masklen; 471 addr_masklen_ntop(&p->addr, bits, s, sizeof(s)); 472 if (p->expiry < now) 473 logit("client %s %s (expired)", s, p->reason); 474 else { 475 logit("client %s %s (%llu secs left)", s, p->reason, 476 (long long)(p->expiry - now)); 477 } 478 } 479 } 480 481 void 482 srclimit_penalty_info(void) 483 { 484 srclimit_penalty_info_for_tree("ipv4", 485 &penalties_by_expiry4, npenalties4); 486 srclimit_penalty_info_for_tree("ipv6", 487 &penalties_by_expiry6, npenalties6); 488 } 489