unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
blacklist.c (22679B)
1 /* 2 * Blacklist support (currently only DNS Blacklists) 3 * (C) Copyright 2015-.. Bram Matthys (Syzop) and the UnrealIRCd team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 1, or (at your option) 8 * any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20 #include "unrealircd.h" 21 #include "dns.h" 22 23 ModuleHeader MOD_HEADER 24 = { 25 "blacklist", 26 "5.0", 27 "Check connecting users against DNS Blacklists", 28 "UnrealIRCd Team", 29 "unrealircd-6", 30 }; 31 32 /* In this module and the config syntax I tried to 'abstract' things 33 * a little, so things could later be extended if we ever want 34 * to introduce another blacklist type (other than DNSBL). 35 * Once that happens, best to re-check/audit the source. 36 */ 37 38 /* Types */ 39 40 typedef enum { 41 DNSBL_RECORD=1, DNSBL_BITMASK=2 42 } DNSBLType; 43 44 typedef struct DNSBL DNSBL; 45 struct DNSBL { 46 char *name; 47 DNSBLType type; 48 int *reply; 49 }; 50 51 typedef union BlacklistBackend BlacklistBackend; 52 union BlacklistBackend 53 { 54 DNSBL *dns; 55 }; 56 57 typedef enum { 58 BLACKLIST_BACKEND_DNS = 1 59 } BlacklistBackendType; 60 61 typedef struct Blacklist Blacklist; 62 struct Blacklist { 63 Blacklist *prev, *next; 64 char *name; 65 BlacklistBackendType backend_type; 66 BlacklistBackend *backend; 67 int action; 68 long ban_time; 69 char *reason; 70 SecurityGroup *except; 71 }; 72 73 /* Blacklist user struct. In the c-ares DNS reply callback we need to pass 74 * some metadata. We can't use client directly there as the client may 75 * be gone already by the time we receive the DNS reply. 76 */ 77 typedef struct BLUser BLUser; 78 struct BLUser { 79 Client *client; 80 int is_ipv6; 81 int refcnt; 82 /* The following save_* fields are used by softbans: */ 83 int save_action; 84 long save_tkltime; 85 char *save_opernotice; 86 char *save_reason; 87 char *save_blacklist; 88 char *save_blacklist_dns_name; 89 int save_blacklist_dns_reply; 90 }; 91 92 /* Global variables */ 93 ModDataInfo *blacklist_md = NULL; 94 Blacklist *conf_blacklist = NULL; 95 96 /* Forward declarations */ 97 int blacklist_config_test(ConfigFile *, ConfigEntry *, int, int *); 98 int blacklist_config_run(ConfigFile *, ConfigEntry *, int); 99 void blacklist_free_conf(void); 100 void delete_blacklist_block(Blacklist *e); 101 void blacklist_md_free(ModData *md); 102 int blacklist_handshake(Client *client); 103 int blacklist_ip_change(Client *client, const char *oldip); 104 int blacklist_quit(Client *client, MessageTag *mtags, const char *comment); 105 int blacklist_preconnect(Client *client); 106 void blacklist_resolver_callback(void *arg, int status, int timeouts, struct hostent *he); 107 int blacklist_start_check(Client *client); 108 int blacklist_dns_request(Client *client, Blacklist *bl); 109 int blacklist_rehash(void); 110 int blacklist_rehash_complete(void); 111 void blacklist_set_handshake_delay(void); 112 void blacklist_free_bluser_if_able(BLUser *bl); 113 114 #define SetBLUser(x, y) do { moddata_client(x, blacklist_md).ptr = y; } while(0) 115 #define BLUSER(x) ((BLUser *)moddata_client(x, blacklist_md).ptr) 116 117 MOD_TEST() 118 { 119 HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, blacklist_config_test); 120 121 CallbackAdd(modinfo->handle, CALLBACKTYPE_BLACKLIST_CHECK, blacklist_start_check); 122 return MOD_SUCCESS; 123 } 124 125 /** Called upon module init */ 126 MOD_INIT() 127 { 128 ModDataInfo mreq; 129 130 MARK_AS_OFFICIAL_MODULE(modinfo); 131 /* This module needs to be permanent. 132 * Not because of UnrealIRCd restrictions, 133 * but because we use c-ares callbacks and the address 134 * of those functions will change if we REHASH. 135 */ 136 ModuleSetOptions(modinfo->handle, MOD_OPT_PERM, 1); 137 138 memset(&mreq, 0, sizeof(mreq)); 139 mreq.name = "blacklist"; 140 mreq.type = MODDATATYPE_CLIENT; 141 mreq.free = blacklist_md_free; 142 blacklist_md = ModDataAdd(modinfo->handle, mreq); 143 if (!blacklist_md) 144 { 145 config_error("could not register blacklist moddata"); 146 return MOD_FAILED; 147 } 148 149 HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, blacklist_config_run); 150 HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, blacklist_handshake); 151 HookAdd(modinfo->handle, HOOKTYPE_IP_CHANGE, 0, blacklist_ip_change); 152 HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, blacklist_preconnect); 153 HookAdd(modinfo->handle, HOOKTYPE_REHASH, 0, blacklist_rehash); 154 HookAdd(modinfo->handle, HOOKTYPE_REHASH_COMPLETE, 0, blacklist_rehash_complete); 155 HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, blacklist_quit); 156 157 return MOD_SUCCESS; 158 } 159 160 /** Called upon module load */ 161 MOD_LOAD() 162 { 163 blacklist_set_handshake_delay(); 164 return MOD_SUCCESS; 165 } 166 167 /** Called upon unload */ 168 MOD_UNLOAD() 169 { 170 blacklist_free_conf(); 171 return MOD_SUCCESS; 172 } 173 174 int blacklist_rehash(void) 175 { 176 blacklist_free_conf(); 177 return 0; 178 } 179 180 int blacklist_rehash_complete(void) 181 { 182 blacklist_set_handshake_delay(); 183 return 0; 184 } 185 186 void blacklist_set_handshake_delay(void) 187 { 188 if ((iConf.handshake_delay == -1) && conf_blacklist) 189 { 190 /* 191 Too noisy? 192 config_status("[blacklist] I'm setting set::handshake-delay to 2 seconds. " 193 "You may wish to set an explicit setting in the configuration file."); 194 config_status("See https://www.unrealircd.org/docs/Set_block#set::handshake-delay"); 195 */ 196 iConf.handshake_delay = 2; 197 } 198 } 199 200 /** Find blacklist { } block */ 201 Blacklist *blacklist_find_block_by_dns(char *name) 202 { 203 Blacklist *d; 204 205 for (d = conf_blacklist; d; d = d->next) 206 if ((d->backend_type == BLACKLIST_BACKEND_DNS) && !strcmp(name, d->backend->dns->name)) 207 return d; 208 209 return NULL; 210 } 211 212 void blacklist_free_conf(void) 213 { 214 Blacklist *d, *d_next; 215 216 for (d = conf_blacklist; d; d = d_next) 217 { 218 d_next = d->next; 219 delete_blacklist_block(d); 220 } 221 conf_blacklist = NULL; 222 } 223 224 void delete_blacklist_block(Blacklist *e) 225 { 226 if (e->backend_type == BLACKLIST_BACKEND_DNS) 227 { 228 if (e->backend->dns) 229 { 230 safe_free(e->backend->dns->name); 231 safe_free(e->backend->dns->reply); 232 safe_free(e->backend->dns); 233 } 234 } 235 236 safe_free(e->backend); 237 238 safe_free(e->name); 239 safe_free(e->reason); 240 free_security_group(e->except); 241 242 safe_free(e); 243 } 244 245 int blacklist_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) 246 { 247 ConfigEntry *cep, *cepp, *ceppp; 248 int errors = 0; 249 char has_reason = 0, has_ban_time = 0, has_action = 0; 250 char has_dns_type = 0, has_dns_reply = 0, has_dns_name = 0; 251 252 if (type != CONFIG_MAIN) 253 return 0; 254 255 if (!ce) 256 return 0; 257 258 if (strcmp(ce->name, "blacklist")) 259 return 0; /* not interested in non-blacklist stuff.. */ 260 261 if (!ce->value) 262 { 263 config_error("%s:%i: blacklist block without name (use: blacklist somename { })", 264 ce->file->filename, ce->line_number); 265 *errs = 1; 266 return -1; 267 } 268 269 /* Now actually go parse the blacklist { } block */ 270 for (cep = ce->items; cep; cep = cep->next) 271 { 272 if (!strcmp(cep->name, "dns")) 273 { 274 for (cepp = cep->items; cepp; cepp = cepp->next) 275 { 276 if (!strcmp(cepp->name, "reply")) 277 { 278 if (has_dns_reply) 279 { 280 /* this is an error (not a warning) */ 281 config_error("%s:%i: blacklist block may contain only one blacklist::dns::reply item. " 282 "You can specify multiple replies by using: reply { 1; 2; 4; };", 283 cepp->file->filename, cepp->line_number); 284 errors++; 285 continue; 286 } 287 if (!cepp->value && !cepp->items) 288 { 289 config_error_blank(cepp->file->filename, cepp->line_number, "blacklist::dns::reply"); 290 errors++; 291 continue; 292 } 293 has_dns_reply = 1; /* we have a reply. now whether it's actually valid is another story.. */ 294 if (cepp->value && cepp->items) 295 { 296 config_error("%s:%i: blacklist::dns::reply must be either using format 'reply 1;' or " 297 "'reply { 1; 2; 4; }; but not both formats at the same time.", 298 cepp->file->filename, cepp->line_number); 299 errors++; 300 continue; 301 } 302 if (cepp->value) 303 { 304 if (atoi(cepp->value) <= 0) 305 { 306 config_error("%s:%i: blacklist::dns::reply must be >0", 307 cepp->file->filename, cepp->line_number); 308 errors++; 309 continue; 310 } 311 } 312 if (cepp->items) 313 { 314 for (ceppp = cepp->items; ceppp; ceppp=ceppp->next) 315 { 316 if (atoi(ceppp->name) <= 0) 317 { 318 config_error("%s:%i: all items in blacklist::dns::reply must be >0", 319 cepp->file->filename, cepp->line_number); 320 errors++; 321 } 322 } 323 } 324 } else 325 if (!cepp->value) 326 { 327 config_error_empty(cepp->file->filename, cepp->line_number, 328 "blacklist::dns", cepp->name); 329 errors++; 330 continue; 331 } else 332 if (!strcmp(cepp->name, "name")) 333 { 334 if (has_dns_name) 335 { 336 config_warn_duplicate(cepp->file->filename, 337 cepp->line_number, "blacklist::dns::name"); 338 } 339 has_dns_name = 1; 340 } else 341 if (!strcmp(cepp->name, "type")) 342 { 343 if (has_dns_type) 344 { 345 config_warn_duplicate(cepp->file->filename, 346 cepp->line_number, "blacklist::dns::type"); 347 } 348 has_dns_type = 1; 349 if (!strcmp(cepp->value, "record")) 350 ; 351 else if (!strcmp(cepp->value, "bitmask")) 352 ; 353 else 354 { 355 config_error("%s:%i: unknown blacklist::dns::type '%s', must be either 'record' or 'bitmask'", 356 cepp->file->filename, cepp->line_number, cepp->value); 357 errors++; 358 } 359 } 360 } 361 } else 362 if (!strcmp(cep->name, "except")) 363 { 364 test_match_block(cf, cep, &errors); 365 } else 366 if (!cep->value) 367 { 368 config_error_empty(cep->file->filename, cep->line_number, 369 "blacklist", cep->name); 370 errors++; 371 continue; 372 } 373 else if (!strcmp(cep->name, "action")) 374 { 375 if (has_action) 376 { 377 config_warn_duplicate(cep->file->filename, 378 cep->line_number, "blacklist::action"); 379 continue; 380 } 381 has_action = 1; 382 if (!banact_stringtoval(cep->value)) 383 { 384 config_error("%s:%i: blacklist::action has unknown action type '%s'", 385 cep->file->filename, cep->line_number, cep->value); 386 errors++; 387 } 388 } 389 else if (!strcmp(cep->name, "ban-time")) 390 { 391 if (has_ban_time) 392 { 393 config_warn_duplicate(cep->file->filename, 394 cep->line_number, "blacklist::ban-time"); 395 continue; 396 } 397 has_ban_time = 1; 398 } 399 else if (!strcmp(cep->name, "reason")) 400 { 401 if (has_reason) 402 { 403 config_warn_duplicate(cep->file->filename, 404 cep->line_number, "blacklist::reason"); 405 continue; 406 } 407 has_reason = 1; 408 } 409 else 410 { 411 config_error_unknown(cep->file->filename, cep->line_number, 412 "blacklist", cep->name); 413 errors++; 414 } 415 } 416 417 if (!has_action) 418 { 419 config_error_missing(ce->file->filename, ce->line_number, 420 "blacklist::action"); 421 errors++; 422 } 423 424 if (!has_reason) 425 { 426 config_error_missing(ce->file->filename, ce->line_number, 427 "blacklist::reason"); 428 errors++; 429 } 430 431 if (!has_dns_name) 432 { 433 config_error_missing(ce->file->filename, ce->line_number, 434 "blacklist::dns::name"); 435 errors++; 436 } 437 438 if (!has_dns_type) 439 { 440 config_error_missing(ce->file->filename, ce->line_number, 441 "blacklist::dns::type"); 442 errors++; 443 } 444 445 if (!has_dns_reply) 446 { 447 config_error_missing(ce->file->filename, ce->line_number, 448 "blacklist::dns::reply"); 449 errors++; 450 } 451 452 *errs = errors; 453 return errors ? -1 : 1; 454 } 455 456 int blacklist_config_run(ConfigFile *cf, ConfigEntry *ce, int type) 457 { 458 ConfigEntry *cep, *cepp, *ceppp; 459 Blacklist *d = NULL; 460 461 if (type != CONFIG_MAIN) 462 return 0; 463 464 if (!ce || !ce->name || strcmp(ce->name, "blacklist")) 465 return 0; /* not interested */ 466 467 d = safe_alloc(sizeof(Blacklist)); 468 safe_strdup(d->name, ce->value); 469 /* set some defaults */ 470 d->action = BAN_ACT_KILL; 471 safe_strdup(d->reason, "Your IP is on a DNS Blacklist"); 472 d->ban_time = 3600; 473 474 /* assume dns for now ;) */ 475 d->backend_type = BLACKLIST_BACKEND_DNS; 476 d->backend = safe_alloc(sizeof(BlacklistBackend)); 477 d->backend->dns = safe_alloc(sizeof(DNSBL)); 478 479 for (cep = ce->items; cep; cep = cep->next) 480 { 481 if (!strcmp(cep->name, "dns")) 482 { 483 for (cepp = cep->items; cepp; cepp = cepp->next) 484 { 485 if (!strcmp(cepp->name, "reply")) 486 { 487 if (cepp->value) 488 { 489 /* single reply */ 490 d->backend->dns->reply = safe_alloc(sizeof(int)*2); 491 d->backend->dns->reply[0] = atoi(cepp->value); 492 d->backend->dns->reply[1] = 0; 493 } else 494 if (cepp->items) 495 { 496 /* (potentially) multiple reply values */ 497 int cnt = 0; 498 for (ceppp = cepp->items; ceppp; ceppp = ceppp->next) 499 { 500 if (ceppp->name) 501 cnt++; 502 } 503 504 if (cnt == 0) 505 abort(); /* impossible */ 506 507 d->backend->dns->reply = safe_alloc(sizeof(int)*(cnt+1)); 508 509 cnt = 0; 510 for (ceppp = cepp->items; ceppp; ceppp = ceppp->next) 511 { 512 d->backend->dns->reply[cnt++] = atoi(ceppp->name); 513 } 514 d->backend->dns->reply[cnt] = 0; 515 } 516 } else 517 if (!strcmp(cepp->name, "type")) 518 { 519 if (!strcmp(cepp->value, "record")) 520 d->backend->dns->type = DNSBL_RECORD; 521 else if (!strcmp(cepp->value, "bitmask")) 522 d->backend->dns->type = DNSBL_BITMASK; 523 } else 524 if (!strcmp(cepp->name, "name")) 525 { 526 safe_strdup(d->backend->dns->name, cepp->value); 527 } 528 } 529 } 530 else if (!strcmp(cep->name, "action")) 531 { 532 d->action = banact_stringtoval(cep->value); 533 } 534 else if (!strcmp(cep->name, "ban-time")) 535 { 536 d->ban_time = config_checkval(cep->value, CFG_TIME); 537 } 538 else if (!strcmp(cep->name, "reason")) 539 { 540 safe_strdup(d->reason, cep->value); 541 } 542 else if (!strcmp(cep->name, "except")) 543 { 544 conf_match_block(cf, cep, &d->except); 545 } 546 } 547 548 AddListItem(d, conf_blacklist); 549 550 return 0; 551 } 552 553 void blacklist_md_free(ModData *md) 554 { 555 BLUser *bl = md->ptr; 556 557 /* Mark bl->client as dead. Free the struct, if able. */ 558 blacklist_free_bluser_if_able(bl); 559 560 md->ptr = NULL; 561 } 562 563 int blacklist_handshake(Client *client) 564 { 565 blacklist_start_check(client); 566 return 0; 567 } 568 569 int blacklist_ip_change(Client *client, const char *oldip) 570 { 571 blacklist_start_check(client); 572 return 0; 573 } 574 575 int blacklist_start_check(Client *client) 576 { 577 Blacklist *bl; 578 579 if (find_tkl_exception(TKL_BLACKLIST, client)) 580 { 581 /* If the user is exempt from DNSBL checking then: 582 * 1) Don't bother checking DNSBL's 583 * 2) Disable handshake delay for this user, since it serves no purpose. 584 */ 585 SetNoHandshakeDelay(client); 586 return 0; 587 } 588 589 if (!BLUSER(client)) 590 { 591 SetBLUser(client, safe_alloc(sizeof(BLUser))); 592 BLUSER(client)->client = client; 593 } 594 595 for (bl = conf_blacklist; bl; bl = bl->next) 596 { 597 /* Stop processing if client is (being) killed already */ 598 if (!BLUSER(client)) 599 break; 600 601 /* Check if user is exempt (then don't bother checking) */ 602 if (user_allowed_by_security_group(client, bl->except)) 603 continue; 604 605 /* Initiate blacklist requests */ 606 if (bl->backend_type == BLACKLIST_BACKEND_DNS) 607 blacklist_dns_request(client, bl); 608 } 609 610 return 0; 611 } 612 613 int blacklist_dns_request(Client *client, Blacklist *d) 614 { 615 char buf[256], wbuf[128]; 616 unsigned int e[8]; 617 char *ip = GetIP(client); 618 619 if (!ip) 620 return 0; 621 622 memset(&e, 0, sizeof(e)); 623 624 if (strchr(ip, '.')) 625 { 626 /* IPv4 */ 627 if (sscanf(ip, "%u.%u.%u.%u", &e[0], &e[1], &e[2], &e[3]) != 4) 628 return 0; 629 630 snprintf(buf, sizeof(buf), "%u.%u.%u.%u.%s", e[3], e[2], e[1], e[0], d->backend->dns->name); 631 } else 632 if (strchr(ip, ':')) 633 { 634 /* IPv6 */ 635 int i; 636 BLUSER(client)->is_ipv6 = 1; 637 if (sscanf(ip, "%x:%x:%x:%x:%x:%x:%x:%x", 638 &e[0], &e[1], &e[2], &e[3], &e[4], &e[5], &e[6], &e[7]) != 8) 639 { 640 return 0; 641 } 642 *buf = '\0'; 643 for (i = 7; i >= 0; i--) 644 { 645 snprintf(wbuf, sizeof(wbuf), "%x.%x.%x.%x.", 646 (unsigned int)(e[i] & 0xf), 647 (unsigned int)((e[i] >> 4) & 0xf), 648 (unsigned int)((e[i] >> 8) & 0xf), 649 (unsigned int)((e[i] >> 12) & 0xf)); 650 strlcat(buf, wbuf, sizeof(buf)); 651 } 652 strlcat(buf, d->backend->dns->name, sizeof(buf)); 653 } 654 else 655 return 0; /* unknown IP format */ 656 657 BLUSER(client)->refcnt++; /* one (more) blacklist result remaining */ 658 659 unreal_gethostbyname(buf, AF_INET, blacklist_resolver_callback, BLUSER(client)); 660 661 return 0; 662 } 663 664 void blacklist_cancel(BLUser *bl) 665 { 666 bl->client = NULL; 667 } 668 669 int blacklist_quit(Client *client, MessageTag *mtags, const char *comment) 670 { 671 if (BLUSER(client)) 672 blacklist_cancel(BLUSER(client)); 673 674 return 0; 675 } 676 677 /** Free the BLUSER() struct, if we are able to do so. 678 * This should only be called if the underlying client is dead or dyeing 679 * and not earlier. 680 * Reasons why we 'are not able' are: refcnt is non-zero, that is: 681 * there is still an outstanding resolver request (eg: slow blacklist). 682 * In that case, no worries, we will be called again after that request 683 * is finished. 684 */ 685 void blacklist_free_bluser_if_able(BLUser *bl) 686 { 687 if (bl->client) 688 bl->client = NULL; 689 690 if (bl->refcnt > 0) 691 return; /* unable, still have DNS requests/replies in-flight */ 692 693 safe_free(bl->save_opernotice); 694 safe_free(bl->save_reason); 695 safe_free(bl); 696 } 697 698 char *getdnsblname(char *p, Client *client) 699 { 700 int dots = 0; 701 int dots_count; 702 703 if (!client) 704 return NULL; 705 706 if (BLUSER(client)->is_ipv6) 707 dots_count = 32; 708 else 709 dots_count = 4; 710 711 for (; *p; p++) 712 { 713 if (*p == '.') 714 { 715 dots++; 716 if (dots == dots_count) 717 return p+1; 718 } 719 } 720 return NULL; 721 } 722 723 /* Parse DNS reply. 724 * A reply will be an A record in the format x.x.x.<reply> 725 */ 726 int blacklist_parse_reply(struct hostent *he, int entry) 727 { 728 char ipbuf[64]; 729 char *p; 730 731 if ((he->h_addrtype != AF_INET) || (he->h_length != 4)) 732 return 0; 733 734 *ipbuf = '\0'; 735 if (!inet_ntop(AF_INET, he->h_addr_list[entry], ipbuf, sizeof(ipbuf))) 736 return 0; 737 738 p = strrchr(ipbuf, '.'); 739 if (!p) 740 return 0; 741 742 return atoi(p+1); 743 } 744 745 /** Take the actual ban action. 746 * Called from blacklist_hit() and for immediate bans and 747 * from blacklist_preconnect() for softbans that need to be delayed 748 * as to give the user the opportunity to do SASL Authentication. 749 */ 750 int blacklist_action(Client *client, char *opernotice, BanAction ban_action, char *ban_reason, long ban_time, 751 char *blacklist, char *blacklist_dns_name, int blacklist_dns_reply) 752 { 753 unreal_log_raw(ULOG_INFO, "blacklist", "BLACKLIST_HIT", client, 754 opernotice, 755 log_data_string("blacklist_name", blacklist), 756 log_data_string("blacklist_dns_name", blacklist_dns_name), 757 log_data_integer("blacklist_dns_reply", blacklist_dns_reply), 758 log_data_string("ban_action", banact_valtostring(ban_action)), 759 log_data_string("ban_reason", ban_reason), 760 log_data_integer("ban_time", ban_time)); 761 if (ban_action == BAN_ACT_WARN) 762 return 0; 763 return place_host_ban(client, ban_action, ban_reason, ban_time); 764 } 765 766 void blacklist_hit(Client *client, Blacklist *bl, int reply) 767 { 768 char opernotice[512], banbuf[512], reply_num[5]; 769 const char *name[6], *value[6]; 770 BLUser *blu = BLUSER(client); 771 772 if (find_tkline_match(client, 1)) 773 return; /* already klined/glined. Don't send the warning from below. */ 774 775 if (IsUser(client)) 776 snprintf(opernotice, sizeof(opernotice), "[Blacklist] IP %s (%s) matches blacklist %s (%s/reply=%d)", 777 GetIP(client), client->name, bl->name, bl->backend->dns->name, reply); 778 else 779 snprintf(opernotice, sizeof(opernotice), "[Blacklist] IP %s matches blacklist %s (%s/reply=%d)", 780 GetIP(client), bl->name, bl->backend->dns->name, reply); 781 782 snprintf(reply_num, sizeof(reply_num), "%d", reply); 783 784 name[0] = "ip"; 785 value[0] = GetIP(client); 786 name[1] = "server"; 787 value[1] = me.name; 788 name[2] = "blacklist"; 789 value[2] = bl->name; 790 name[3] = "dnsname"; 791 value[3] = bl->backend->dns->name; 792 name[4] = "dnsreply"; 793 value[4] = reply_num; 794 name[5] = NULL; 795 value[5] = NULL; 796 /* when adding more, be sure to update the array elements number in the definition of const char *name[] and value[] */ 797 798 buildvarstring(bl->reason, banbuf, sizeof(banbuf), name, value); 799 800 if (IsSoftBanAction(bl->action) && blu) 801 { 802 /* For soft bans, delay the action until later (so user can do SASL auth) */ 803 blu->save_action = bl->action; 804 blu->save_tkltime = bl->ban_time; 805 safe_strdup(blu->save_opernotice, opernotice); 806 safe_strdup(blu->save_reason, banbuf); 807 safe_strdup(blu->save_blacklist, bl->name); 808 safe_strdup(blu->save_blacklist_dns_name, bl->backend->dns->name); 809 blu->save_blacklist_dns_reply = reply; 810 } else { 811 /* Otherwise, execute the action immediately */ 812 blacklist_action(client, opernotice, bl->action, banbuf, bl->ban_time, bl->name, bl->backend->dns->name, reply); 813 } 814 } 815 816 void blacklist_process_result(Client *client, int status, struct hostent *he) 817 { 818 Blacklist *bl; 819 char *domain; 820 int reply; 821 int i; 822 int replycnt; 823 824 if ((status != 0) || (he->h_length != 4) || !he->h_name) 825 return; /* invalid reply */ 826 827 domain = getdnsblname(he->h_name, client); 828 if (!domain) 829 return; /* odd */ 830 bl = blacklist_find_block_by_dns(domain); 831 if (!bl) 832 return; /* possibly just rehashed and the blacklist block is gone now */ 833 834 /* walk through all replies for this record... until we have a hit */ 835 for (replycnt=0; he->h_addr_list[replycnt]; replycnt++) 836 { 837 reply = blacklist_parse_reply(he, replycnt); 838 839 for (i = 0; bl->backend->dns->reply[i]; i++) 840 { 841 if ((bl->backend->dns->reply[i] == -1) || 842 ( (bl->backend->dns->type == DNSBL_BITMASK) && (reply & bl->backend->dns->reply[i]) ) || 843 ( (bl->backend->dns->type == DNSBL_RECORD) && (bl->backend->dns->reply[i] == reply) ) ) 844 { 845 blacklist_hit(client, bl, reply); 846 return; 847 } 848 } 849 } 850 } 851 852 void blacklist_resolver_callback(void *arg, int status, int timeouts, struct hostent *he) 853 { 854 BLUser *blu = (BLUser *)arg; 855 Client *client = blu->client; 856 857 blu->refcnt--; /* one less outstanding DNS request remaining */ 858 859 /* If we are the last to resolve something and the client is gone 860 * already then free the struct. 861 */ 862 if ((blu->refcnt == 0) && !client) 863 blacklist_free_bluser_if_able(blu); 864 865 blu = NULL; 866 867 if (!client) 868 return; /* Client left already */ 869 /* ^^ note: do not merge this with the other 'if' a few lines up (refcnt!) */ 870 871 blacklist_process_result(client, status, he); 872 } 873 874 int blacklist_preconnect(Client *client) 875 { 876 BLUser *blu = BLUSER(client); 877 878 if (!blu || !blu->save_action) 879 return HOOK_CONTINUE; 880 881 /* There was a pending softban... has the user authenticated via SASL by now? */ 882 if (IsLoggedIn(client)) 883 return HOOK_CONTINUE; /* yup, so the softban does not apply. */ 884 885 if (blacklist_action(client, blu->save_opernotice, blu->save_action, blu->save_reason, blu->save_tkltime, 886 blu->save_blacklist, blu->save_blacklist_dns_name, blu->save_blacklist_dns_reply)) 887 { 888 return HOOK_DENY; 889 } 890 return HOOK_CONTINUE; /* exempt */ 891 }