unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
server.c (72936B)
1 /* 2 * IRC - Internet Relay Chat, src/modules/server.c 3 * (C) 2004-present The UnrealIRCd Team 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 #include "unrealircd.h" 24 25 /* Definitions */ 26 typedef enum AutoConnectStrategy { 27 AUTOCONNECT_PARALLEL = 0, 28 AUTOCONNECT_SEQUENTIAL = 1, 29 AUTOCONNECT_SEQUENTIAL_FALLBACK = 2 30 } AutoConnectStrategy; 31 32 typedef struct cfgstruct cfgstruct; 33 struct cfgstruct { 34 AutoConnectStrategy autoconnect_strategy; 35 long connect_timeout; 36 long handshake_timeout; 37 }; 38 39 typedef struct ConfigItem_deny_link ConfigItem_deny_link; 40 struct ConfigItem_deny_link { 41 ConfigItem_deny_link *prev, *next; 42 ConfigFlag_except flag; 43 ConfigItem_mask *mask; 44 CRuleNode *rule; /**< parsed crule */ 45 char *prettyrule; /**< human printable version */ 46 char *reason; /**< Reason for the deny link */ 47 }; 48 49 /* Forward declarations */ 50 void server_config_setdefaults(cfgstruct *cfg); 51 void server_config_free(); 52 int server_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs); 53 int server_config_run(ConfigFile *cf, ConfigEntry *ce, int type); 54 EVENT(server_autoconnect); 55 EVENT(server_handshake_timeout); 56 void send_channel_modes_sjoin3(Client *to, Channel *channel); 57 CMD_FUNC(cmd_server); 58 CMD_FUNC(cmd_sid); 59 ConfigItem_link *_verify_link(Client *client); 60 void _send_protoctl_servers(Client *client, int response); 61 void _send_server_message(Client *client); 62 void _introduce_user(Client *to, Client *acptr); 63 int _check_deny_version(Client *cptr, char *software, int protocol, char *flags); 64 void _broadcast_sinfo(Client *acptr, Client *to, Client *except); 65 int server_sync(Client *cptr, ConfigItem_link *conf, int incoming); 66 void tls_link_notification_verify(Client *acptr, ConfigItem_link *aconf); 67 void server_generic_free(ModData *m); 68 int server_post_connect(Client *client); 69 void _connect_server(ConfigItem_link *aconf, Client *by, struct hostent *hp); 70 static int connect_server_helper(ConfigItem_link *, Client *); 71 int _is_services_but_not_ulined(Client *client); 72 const char *_check_deny_link(ConfigItem_link *link, int auto_connect); 73 int server_stats_denylink_all(Client *client, const char *para); 74 int server_stats_denylink_auto(Client *client, const char *para); 75 76 /* Global variables */ 77 static cfgstruct cfg; 78 static char *last_autoconnect_server = NULL; 79 static ConfigItem_deny_link *conf_deny_link = NULL; 80 81 ModuleHeader MOD_HEADER 82 = { 83 "server", 84 "5.0", 85 "command /server", 86 "UnrealIRCd Team", 87 "unrealircd-6", 88 }; 89 90 MOD_TEST() 91 { 92 MARK_AS_OFFICIAL_MODULE(modinfo); 93 EfunctionAddVoid(modinfo->handle, EFUNC_SEND_PROTOCTL_SERVERS, _send_protoctl_servers); 94 EfunctionAddVoid(modinfo->handle, EFUNC_SEND_SERVER_MESSAGE, _send_server_message); 95 EfunctionAddPVoid(modinfo->handle, EFUNC_VERIFY_LINK, TO_PVOIDFUNC(_verify_link)); 96 EfunctionAddVoid(modinfo->handle, EFUNC_INTRODUCE_USER, _introduce_user); 97 EfunctionAdd(modinfo->handle, EFUNC_CHECK_DENY_VERSION, _check_deny_version); 98 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_SINFO, _broadcast_sinfo); 99 EfunctionAddVoid(modinfo->handle, EFUNC_CONNECT_SERVER, _connect_server); 100 EfunctionAdd(modinfo->handle, EFUNC_IS_SERVICES_BUT_NOT_ULINED, _is_services_but_not_ulined); 101 EfunctionAddConstString(modinfo->handle, EFUNC_CHECK_DENY_LINK, _check_deny_link); 102 HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, server_config_test); 103 return MOD_SUCCESS; 104 } 105 106 MOD_INIT() 107 { 108 MARK_AS_OFFICIAL_MODULE(modinfo); 109 LoadPersistentPointer(modinfo, last_autoconnect_server, server_generic_free); 110 server_config_setdefaults(&cfg); 111 HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, server_config_run); 112 HookAdd(modinfo->handle, HOOKTYPE_POST_SERVER_CONNECT, 0, server_post_connect); 113 HookAdd(modinfo->handle, HOOKTYPE_STATS, 0, server_stats_denylink_all); 114 HookAdd(modinfo->handle, HOOKTYPE_STATS, 0, server_stats_denylink_auto); 115 CommandAdd(modinfo->handle, "SERVER", cmd_server, MAXPARA, CMD_UNREGISTERED|CMD_SERVER); 116 CommandAdd(modinfo->handle, "SID", cmd_sid, MAXPARA, CMD_SERVER); 117 118 return MOD_SUCCESS; 119 } 120 121 MOD_LOAD() 122 { 123 EventAdd(modinfo->handle, "server_autoconnect", server_autoconnect, NULL, 2000, 0); 124 EventAdd(modinfo->handle, "server_handshake_timeout", server_handshake_timeout, NULL, 1000, 0); 125 return MOD_SUCCESS; 126 } 127 128 MOD_UNLOAD() 129 { 130 server_config_free(); 131 SavePersistentPointer(modinfo, last_autoconnect_server); 132 return MOD_SUCCESS; 133 } 134 135 /** Convert 'str' to a AutoConnectStrategy value. 136 * @param str The string, eg "parallel" 137 * @returns a valid AutoConnectStrategy value or -1 if not found. 138 */ 139 AutoConnectStrategy autoconnect_strategy_strtoval(char *str) 140 { 141 if (!strcmp(str, "parallel")) 142 return AUTOCONNECT_PARALLEL; 143 if (!strcmp(str, "sequential")) 144 return AUTOCONNECT_SEQUENTIAL; 145 if (!strcmp(str, "sequential-fallback")) 146 return AUTOCONNECT_SEQUENTIAL_FALLBACK; 147 return -1; 148 } 149 150 /** Convert an AutoConnectStrategy value to a string. 151 * @param val The value to convert to a string 152 * @returns a string, such as "parallel". 153 */ 154 char *autoconnect_strategy_valtostr(AutoConnectStrategy val) 155 { 156 switch (val) 157 { 158 case AUTOCONNECT_PARALLEL: 159 return "parallel"; 160 case AUTOCONNECT_SEQUENTIAL: 161 return "sequential"; 162 case AUTOCONNECT_SEQUENTIAL_FALLBACK: 163 return "sequential-fallback"; 164 default: 165 return "???"; 166 } 167 } 168 169 void server_config_setdefaults(cfgstruct *cfg) 170 { 171 cfg->autoconnect_strategy = AUTOCONNECT_SEQUENTIAL; 172 cfg->connect_timeout = 10; 173 cfg->handshake_timeout = 20; 174 } 175 176 void server_config_free(void) 177 { 178 ConfigItem_deny_link *d, *d_next; 179 180 for (d = conf_deny_link; d; d = d_next) 181 { 182 d_next = d->next; 183 unreal_delete_masks(d->mask); 184 crule_free(&d->rule); 185 safe_free(d->prettyrule); 186 safe_free(d->reason); 187 DelListItem(d, conf_deny_link); 188 safe_free(d); 189 } 190 conf_deny_link = NULL; 191 } 192 193 int server_config_test_set_server_linking(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) 194 { 195 int errors = 0; 196 ConfigEntry *cep; 197 198 for (cep = ce->items; cep; cep = cep->next) 199 { 200 if (!cep->value) 201 { 202 config_error("%s:%i: blank set::server-linking::%s without value", 203 cep->file->filename, cep->line_number, cep->name); 204 errors++; 205 continue; 206 } else 207 if (!strcmp(cep->name, "autoconnect-strategy")) 208 { 209 if (autoconnect_strategy_strtoval(cep->value) < 0) 210 { 211 config_error("%s:%i: set::server-linking::autoconnect-strategy: invalid value '%s'. " 212 "Should be one of: parallel", 213 cep->file->filename, cep->line_number, cep->value); 214 errors++; 215 continue; 216 } 217 } else 218 if (!strcmp(cep->name, "connect-timeout")) 219 { 220 long v = config_checkval(cep->value, CFG_TIME); 221 if ((v < 5) || (v > 30)) 222 { 223 config_error("%s:%i: set::server-linking::connect-timeout should be between 5 and 60 seconds", 224 cep->file->filename, cep->line_number); 225 errors++; 226 continue; 227 } 228 } else 229 if (!strcmp(cep->name, "handshake-timeout")) 230 { 231 long v = config_checkval(cep->value, CFG_TIME); 232 if ((v < 10) || (v > 120)) 233 { 234 config_error("%s:%i: set::server-linking::handshake-timeout should be between 10 and 120 seconds", 235 cep->file->filename, cep->line_number); 236 errors++; 237 continue; 238 } 239 } else 240 { 241 config_error("%s:%i: unknown directive set::server-linking::%s", 242 cep->file->filename, cep->line_number, cep->name); 243 errors++; 244 continue; 245 } 246 } 247 248 *errs = errors; 249 return errors ? -1 : 1; 250 } 251 252 int server_config_run_set_server_linking(ConfigFile *cf, ConfigEntry *ce, int type) 253 { 254 ConfigEntry *cep; 255 256 for (cep = ce->items; cep; cep = cep->next) 257 { 258 if (!strcmp(cep->name, "autoconnect-strategy")) 259 { 260 cfg.autoconnect_strategy = autoconnect_strategy_strtoval(cep->value); 261 } else 262 if (!strcmp(cep->name, "connect-timeout")) 263 { 264 cfg.connect_timeout = config_checkval(cep->value, CFG_TIME); 265 } else 266 if (!strcmp(cep->name, "handshake-timeout")) 267 { 268 cfg.handshake_timeout = config_checkval(cep->value, CFG_TIME); 269 } 270 } 271 272 return 1; 273 } 274 275 int server_config_test_deny_link(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) 276 { 277 int errors = 0; 278 ConfigEntry *cep; 279 char has_mask = 0, has_rule = 0, has_type = 0; 280 281 for (cep = ce->items; cep; cep = cep->next) 282 { 283 if (!cep->items) 284 { 285 if (config_is_blankorempty(cep, "deny link")) 286 { 287 errors++; 288 continue; 289 } 290 else if (!strcmp(cep->name, "mask")) 291 { 292 has_mask = 1; 293 } else if (!strcmp(cep->name, "rule")) 294 { 295 int val = 0; 296 if (has_rule) 297 { 298 config_warn_duplicate(cep->file->filename, 299 cep->line_number, "deny link::rule"); 300 continue; 301 } 302 has_rule = 1; 303 if ((val = crule_test(cep->value))) 304 { 305 config_error("%s:%i: deny link::rule contains an invalid expression: %s", 306 cep->file->filename, 307 cep->line_number, 308 crule_errstring(val)); 309 errors++; 310 } 311 } 312 else if (!strcmp(cep->name, "type")) 313 { 314 if (has_type) 315 { 316 config_warn_duplicate(cep->file->filename, 317 cep->line_number, "deny link::type"); 318 continue; 319 } 320 has_type = 1; 321 if (!strcmp(cep->value, "auto")) 322 ; 323 else if (!strcmp(cep->value, "all")) 324 ; 325 else { 326 config_status("%s:%i: unknown deny link type", 327 cep->file->filename, cep->line_number); 328 errors++; 329 } 330 } else if (!strcmp(cep->name, "reason")) 331 { 332 } 333 else 334 { 335 config_error_unknown(cep->file->filename, 336 cep->line_number, "deny link", cep->name); 337 errors++; 338 } 339 } 340 else 341 { 342 // Sections 343 if (!strcmp(cep->name, "mask")) 344 { 345 if (cep->value || cep->items) 346 has_mask = 1; 347 } 348 else 349 { 350 config_error_unknown(cep->file->filename, 351 cep->line_number, "deny link", cep->name); 352 errors++; 353 continue; 354 } 355 } 356 } 357 if (!has_mask) 358 { 359 config_error_missing(ce->file->filename, ce->line_number, 360 "deny link::mask"); 361 errors++; 362 } 363 if (!has_rule) 364 { 365 config_error_missing(ce->file->filename, ce->line_number, 366 "deny link::rule"); 367 errors++; 368 } 369 if (!has_type) 370 { 371 config_error_missing(ce->file->filename, ce->line_number, 372 "deny link::type"); 373 errors++; 374 } 375 376 *errs = errors; 377 return errors ? -1 : 1; 378 } 379 380 int server_config_run_deny_link(ConfigFile *cf, ConfigEntry *ce, int type) 381 { 382 ConfigEntry *cep; 383 ConfigItem_deny_link *deny; 384 385 deny = safe_alloc(sizeof(ConfigItem_deny_link)); 386 387 for (cep = ce->items; cep; cep = cep->next) 388 { 389 if (!strcmp(cep->name, "mask")) 390 { 391 unreal_add_masks(&deny->mask, cep); 392 } 393 else if (!strcmp(cep->name, "rule")) 394 { 395 deny->rule = crule_parse(cep->value); 396 safe_strdup(deny->prettyrule, cep->value); 397 } 398 else if (!strcmp(cep->name, "reason")) 399 { 400 safe_strdup(deny->reason, cep->value); 401 } 402 else if (!strcmp(cep->name, "type")) { 403 if (!strcmp(cep->value, "all")) 404 deny->flag.type = CRULE_ALL; 405 else if (!strcmp(cep->value, "auto")) 406 deny->flag.type = CRULE_AUTO; 407 } 408 } 409 410 /* Set a default reason, if needed */ 411 if (!deny->reason) 412 safe_strdup(deny->reason, "Denied"); 413 414 AddListItem(deny, conf_deny_link); 415 return 1; 416 } 417 418 int server_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) 419 { 420 if ((type == CONFIG_SET) && !strcmp(ce->name, "server-linking")) 421 return server_config_test_set_server_linking(cf, ce, type, errs); 422 423 if ((type == CONFIG_DENY) && !strcmp(ce->value, "link")) 424 return server_config_test_deny_link(cf, ce, type, errs); 425 426 return 0; /* not for us */ 427 } 428 429 int server_config_run(ConfigFile *cf, ConfigEntry *ce, int type) 430 { 431 if ((type == CONFIG_SET) && ce && !strcmp(ce->name, "server-linking")) 432 return server_config_run_set_server_linking(cf, ce, type); 433 434 if ((type == CONFIG_DENY) && !strcmp(ce->value, "link")) 435 return server_config_run_deny_link(cf, ce, type); 436 437 return 0; /* not for us */ 438 } 439 440 int server_needs_linking(ConfigItem_link *aconf) 441 { 442 Client *client; 443 ConfigItem_class *class; 444 445 /* We're only interested in autoconnect blocks that also have 446 * a valid link::outgoing configuration. We also ignore 447 * temporary link blocks (not that they should exist...). 448 */ 449 if (!(aconf->outgoing.options & CONNECT_AUTO) || 450 (!aconf->outgoing.hostname && !aconf->outgoing.file) || 451 (aconf->flag.temporary == 1)) 452 return 0; 453 454 class = aconf->class; 455 456 /* Never do more than one connection attempt per <connfreq> seconds (for the same server) */ 457 if ((aconf->hold > TStime())) 458 return 0; 459 460 aconf->hold = TStime() + class->connfreq; 461 462 client = find_client(aconf->servername, NULL); 463 if (client) 464 return 0; /* Server already connected (or connecting) */ 465 466 if (class->clients >= class->maxclients) 467 return 0; /* Class is full */ 468 469 /* Check connect rules to see if we're allowed to try the link */ 470 if (check_deny_link(aconf, 1)) 471 return 0; 472 473 /* Yes, this server is a linking candidate */ 474 return 1; 475 } 476 477 void server_autoconnect_parallel(void) 478 { 479 ConfigItem_link *aconf; 480 481 for (aconf = conf_link; aconf; aconf = aconf->next) 482 { 483 if (!server_needs_linking(aconf)) 484 continue; 485 486 connect_server(aconf, NULL, NULL); 487 } 488 } 489 490 /** Find first (valid) autoconnect server in link blocks. 491 * This function should not be used directly. It is a helper function 492 * for find_next_autoconnect_server(). 493 */ 494 ConfigItem_link *find_first_autoconnect_server(void) 495 { 496 ConfigItem_link *aconf; 497 498 for (aconf = conf_link; aconf; aconf = aconf->next) 499 { 500 if (!server_needs_linking(aconf)) 501 continue; 502 return aconf; /* found! */ 503 } 504 return NULL; /* none */ 505 } 506 507 /** Find next server that we should try to autoconnect to. 508 * Taking into account that we last tried server 'current'. 509 * @param current Server the previous autoconnect attempt was made to 510 * @returns A link block, or NULL if no servers are suitable. 511 */ 512 ConfigItem_link *find_next_autoconnect_server(char *current) 513 { 514 ConfigItem_link *aconf; 515 516 /* If the current autoconnect server is NULL then 517 * just find whichever valid server is first. 518 */ 519 if (current == NULL) 520 return find_first_autoconnect_server(); 521 522 /* Next code is a bit convulted, it would have 523 * been easier if conf_link was a circular list ;) 524 */ 525 526 /* Otherwise, walk the list up to 'current' */ 527 for (aconf = conf_link; aconf; aconf = aconf->next) 528 { 529 if (!strcmp(aconf->servername, current)) 530 break; 531 } 532 533 /* If the 'current' server dissapeared, then let's 534 * just pick the first one from the list. 535 * It is a rare event to have the link { } block 536 * removed of a server that we just happened to 537 * try to link to before, so we can afford to do 538 * it this way. 539 */ 540 if (!aconf) 541 return find_first_autoconnect_server(); 542 543 /* Check the remainder for the list, in other words: 544 * check all servers after 'current' if they are 545 * ready for an outgoing connection attempt... 546 */ 547 for (aconf = aconf->next; aconf; aconf = aconf->next) 548 { 549 if (!server_needs_linking(aconf)) 550 continue; 551 return aconf; /* found! */ 552 } 553 554 /* If we get here then there are no valid servers 555 * after 'current', so now check for before 'current' 556 * (and including 'current', since we may 557 * have to autoconnect to that one again, 558 * eg if it is the only autoconnect server)... 559 */ 560 for (aconf = conf_link; aconf; aconf = aconf->next) 561 { 562 if (!server_needs_linking(aconf)) 563 { 564 if (!strcmp(aconf->servername, current)) 565 break; /* need to stop here */ 566 continue; 567 } 568 return aconf; /* found! */ 569 } 570 571 return NULL; /* none */ 572 } 573 574 /** Check if we are currently connecting to a server (outgoing). 575 * This function takes into account not only an outgoing TCP/IP connect 576 * or TLS handshake, but also if we are 'somewhat connected' to that 577 * server but have not completed the full sync, eg we may still need 578 * to receive SIDs or other sync data. 579 * NOTE: This implicitly assumes that outgoing links only go to 580 * servers that will (eventually) send "EOS". 581 * Should be a reasonable assumption given that in nearly all 582 * cases we only connect to UnrealIRCd servers for the outgoing 583 * case, as services are "always" incoming links. 584 * @returns 1 if an outgoing link is in progress, 0 if not. 585 */ 586 int current_outgoing_link_in_process(void) 587 { 588 Client *client; 589 590 list_for_each_entry(client, &unknown_list, lclient_node) 591 { 592 if (client->server && *client->server->by && client->local->creationtime && 593 (IsConnecting(client) || IsTLSConnectHandshake(client) || !IsSynched(client))) 594 { 595 return 1; 596 } 597 } 598 599 list_for_each_entry(client, &server_list, special_node) 600 { 601 if (client->server && *client->server->by && client->local->creationtime && 602 (IsConnecting(client) || IsTLSConnectHandshake(client) || !IsSynched(client))) 603 { 604 return 1; 605 } 606 } 607 608 return 0; 609 } 610 611 void server_autoconnect_sequential(void) 612 { 613 ConfigItem_link *aconf; 614 615 if (current_outgoing_link_in_process()) 616 return; 617 618 /* We are currently not in the process of doing an outgoing connect, 619 * let's see if we need to connect to somewhere... 620 */ 621 aconf = find_next_autoconnect_server(last_autoconnect_server); 622 if (aconf == NULL) 623 return; /* No server to connect to at this time */ 624 625 /* Start outgoing link attempt */ 626 safe_strdup(last_autoconnect_server, aconf->servername); 627 connect_server(aconf, NULL, NULL); 628 } 629 630 /** Perform autoconnect to servers that are not linked yet. */ 631 EVENT(server_autoconnect) 632 { 633 switch (cfg.autoconnect_strategy) 634 { 635 case AUTOCONNECT_PARALLEL: 636 server_autoconnect_parallel(); 637 break; 638 case AUTOCONNECT_SEQUENTIAL: 639 /* Fallback is the same as sequential but we reset last_autoconnect_server on connect */ 640 case AUTOCONNECT_SEQUENTIAL_FALLBACK: 641 server_autoconnect_sequential(); 642 break; 643 } 644 } 645 646 EVENT(server_handshake_timeout) 647 { 648 Client *client, *next; 649 650 list_for_each_entry_safe(client, next, &unknown_list, lclient_node) 651 { 652 /* We are only interested in outgoing server connects */ 653 if (!client->server || !*client->server->by || !client->local->creationtime) 654 continue; 655 656 /* Handle set::server-linking::connect-timeout */ 657 if ((IsConnecting(client) || IsTLSConnectHandshake(client)) && 658 ((TStime() - client->local->creationtime) >= cfg.connect_timeout)) 659 { 660 /* If this is a connect timeout to an outgoing server then notify ops & log it */ 661 unreal_log(ULOG_INFO, "link", "LINK_CONNECT_TIMEOUT", client, 662 "Connect timeout while trying to link to server '$client' ($client.ip)"); 663 664 exit_client(client, NULL, "Connection timeout"); 665 continue; 666 } 667 668 /* Handle set::server-linking::handshake-timeout */ 669 if ((TStime() - client->local->creationtime) >= cfg.handshake_timeout) 670 { 671 /* If this is a handshake timeout to an outgoing server then notify ops & log it */ 672 unreal_log(ULOG_INFO, "link", "LINK_HANDSHAKE_TIMEOUT", client, 673 "Connect handshake timeout while trying to link to server '$client' ($client.ip)"); 674 675 exit_client(client, NULL, "Handshake Timeout"); 676 continue; 677 } 678 } 679 } 680 681 /** Check deny version { } blocks. 682 * @param cptr Client (a server) 683 * @param software Software version in use (can be NULL) 684 * @param protoctol UnrealIRCd protocol version in use (can be 0) 685 * @param flags Server flags (hardly ever used, can be NULL) 686 * @returns 1 if link is denied (client is already killed), 0 if not. 687 */ 688 int _check_deny_version(Client *cptr, char *software, int protocol, char *flags) 689 { 690 ConfigItem_deny_version *vlines; 691 692 for (vlines = conf_deny_version; vlines; vlines = vlines->next) 693 { 694 if (match_simple(vlines->mask, cptr->name)) 695 break; 696 } 697 698 if (vlines) 699 { 700 char *proto = vlines->version; 701 char *vflags = vlines->flags; 702 int result = 0, i; 703 switch (*proto) 704 { 705 case '<': 706 proto++; 707 if (protocol < atoi(proto)) 708 result = 1; 709 break; 710 case '>': 711 proto++; 712 if (protocol > atoi(proto)) 713 result = 1; 714 break; 715 case '=': 716 proto++; 717 if (protocol == atoi(proto)) 718 result = 1; 719 break; 720 case '!': 721 proto++; 722 if (protocol != atoi(proto)) 723 result = 1; 724 break; 725 default: 726 if (protocol == atoi(proto)) 727 result = 1; 728 break; 729 } 730 if (protocol == 0 || *proto == '*') 731 result = 0; 732 733 if (result) 734 { 735 exit_client(cptr, NULL, "Denied by deny version { } block"); 736 return 0; 737 } 738 739 if (flags) 740 { 741 for (i = 0; vflags[i]; i++) 742 { 743 if (vflags[i] == '!') 744 { 745 i++; 746 if (strchr(flags, vflags[i])) { 747 result = 1; 748 break; 749 } 750 } 751 else if (!strchr(flags, vflags[i])) 752 { 753 result = 1; 754 break; 755 } 756 } 757 758 if (*vflags == '*' || !strcmp(flags, "0")) 759 result = 0; 760 } 761 762 if (result) 763 { 764 exit_client(cptr, NULL, "Denied by deny version { } block"); 765 return 0; 766 } 767 } 768 769 return 1; 770 } 771 772 /** Send our PROTOCTL SERVERS=x,x,x,x stuff. 773 * When response is set, it will be PROTOCTL SERVERS=*x,x,x (mind the asterisk). 774 */ 775 void _send_protoctl_servers(Client *client, int response) 776 { 777 char buf[512]; 778 Client *acptr; 779 int sendit = 1; 780 781 sendto_one(client, NULL, "PROTOCTL EAUTH=%s,%d,%s%s,UnrealIRCd-%s", 782 me.name, UnrealProtocol, serveropts, extraflags ? extraflags : "", buildid); 783 784 ircsnprintf(buf, sizeof(buf), "PROTOCTL SERVERS=%s", response ? "*" : ""); 785 786 list_for_each_entry(acptr, &global_server_list, client_node) 787 { 788 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s,", acptr->id); 789 sendit = 1; 790 if (strlen(buf) > sizeof(buf)-12) 791 { 792 if (buf[strlen(buf)-1] == ',') 793 buf[strlen(buf)-1] = '\0'; 794 sendto_one(client, NULL, "%s", buf); 795 /* We use the asterisk here too for continuation lines */ 796 ircsnprintf(buf, sizeof(buf), "PROTOCTL SERVERS=*"); 797 sendit = 0; 798 } 799 } 800 801 /* Remove final comma (if any) */ 802 if (buf[strlen(buf)-1] == ',') 803 buf[strlen(buf)-1] = '\0'; 804 805 if (sendit) 806 sendto_one(client, NULL, "%s", buf); 807 } 808 809 void _send_server_message(Client *client) 810 { 811 if (client->server && client->server->flags.server_sent) 812 { 813 #ifdef DEBUGMODE 814 abort(); 815 #endif 816 return; 817 } 818 819 sendto_one(client, NULL, "SERVER %s 1 :U%d-%s%s-%s %s", 820 me.name, UnrealProtocol, serveropts, extraflags ? extraflags : "", me.id, me.info); 821 822 if (client->server) 823 client->server->flags.server_sent = 1; 824 } 825 826 #define LINK_DEFAULT_ERROR_MSG "Link denied (No link block found with your server name or link::incoming::mask did not match)" 827 828 /** Verify server link. 829 * This does authentication and authorization checks. 830 * @param client The client which issued the command 831 * @returns On successfull authentication, the link block is returned. On failure NULL is returned (client has been killed!). 832 */ 833 ConfigItem_link *_verify_link(Client *client) 834 { 835 ConfigItem_link *link, *orig_link; 836 Client *acptr = NULL, *ocptr = NULL; 837 ConfigItem_ban *bconf; 838 839 /* We set the sockhost here so you can have incoming masks based on hostnames. 840 * Perhaps a bit late to do it here, but does anyone care? 841 */ 842 if (client->local->hostp && client->local->hostp->h_name) 843 set_sockhost(client, client->local->hostp->h_name); 844 845 if (!client->local->passwd) 846 { 847 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_NO_PASSWORD", client, 848 "Link with server $client.details denied: No password provided. Protocol error."); 849 exit_client(client, NULL, "Missing password"); 850 return NULL; 851 } 852 853 if (client->server && client->server->conf) 854 { 855 /* This is an outgoing connect so we already know what link block we are 856 * dealing with. It's the one in: client->server->conf 857 */ 858 859 /* Actually we still need to double check the servername to avoid confusion. */ 860 if (strcasecmp(client->name, client->server->conf->servername)) 861 { 862 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_SERVERNAME_MISMATCH", client, 863 "Link with server $client.details denied: " 864 "Outgoing connect from link block '$link_block' but server " 865 "introduced itself as '$client'. Server name mismatch.", 866 log_data_link_block(client->server->conf)); 867 exit_client_fmt(client, NULL, "Servername (%s) does not match name in my link block (%s)", 868 client->name, client->server->conf->servername); 869 return NULL; 870 } 871 link = client->server->conf; 872 goto skip_host_check; 873 } else { 874 /* Hunt the linkblock down ;) */ 875 link = find_link(client->name); 876 } 877 878 if (!link) 879 { 880 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_UNKNOWN_SERVER", client, 881 "Link with server $client.details denied: No link block named '$client'"); 882 exit_client(client, NULL, LINK_DEFAULT_ERROR_MSG); 883 return NULL; 884 } 885 886 if (!link->incoming.match) 887 { 888 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_NO_INCOMING", client, 889 "Link with server $client.details denied: Link block exists, but there is no link::incoming::match set.", 890 log_data_link_block(link)); 891 exit_client(client, NULL, LINK_DEFAULT_ERROR_MSG); 892 return NULL; 893 } 894 895 orig_link = link; 896 if (!user_allowed_by_security_group(client, link->incoming.match)) 897 { 898 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_INCOMING_MASK_MISMATCH", client, 899 "Link with server $client.details denied: Server is in link block but link::incoming::mask didn't match", 900 log_data_link_block(orig_link)); 901 exit_client(client, NULL, LINK_DEFAULT_ERROR_MSG); 902 return NULL; 903 } 904 905 skip_host_check: 906 /* Try to authenticate the server... */ 907 if (!Auth_Check(client, link->auth, client->local->passwd)) 908 { 909 /* Let's help admins a bit with a good error message in case 910 * they mix different authentication systems (plaintext password 911 * vs an "TLS Auth type" like spkifp/tlsclientcert/tlsclientcertfp). 912 * The 'if' statement below is a bit complex but it consists of 2 things: 913 * 1. Check if our side expects a plaintext password but we did not receive one 914 * 2. Check if our side expects a non-plaintext password but we did receive one 915 */ 916 if (((link->auth->type == AUTHTYPE_PLAINTEXT) && client->local->passwd && !strcmp(client->local->passwd, "*")) || 917 ((link->auth->type != AUTHTYPE_PLAINTEXT) && client->local->passwd && strcmp(client->local->passwd, "*"))) 918 { 919 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_AUTH_FAILED", client, 920 "Link with server $client.details denied: Authentication failed: $auth_failure_msg", 921 log_data_string("auth_failure_msg", "different password types on both sides of the link\n" 922 "Read https://www.unrealircd.org/docs/FAQ#auth-fail-mixed for more information"), 923 log_data_link_block(link)); 924 } else 925 if (link->auth->type == AUTHTYPE_SPKIFP) 926 { 927 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_AUTH_FAILED", client, 928 "Link with server $client.details denied: Authentication failed: $auth_failure_msg", 929 log_data_string("auth_failure_msg", "spkifp mismatch"), 930 log_data_link_block(link)); 931 } else 932 if (link->auth->type == AUTHTYPE_TLS_CLIENTCERT) 933 { 934 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_AUTH_FAILED", client, 935 "Link with server $client.details denied: Authentication failed: $auth_failure_msg", 936 log_data_string("auth_failure_msg", "tlsclientcert mismatch"), 937 log_data_link_block(link)); 938 } else 939 if (link->auth->type == AUTHTYPE_TLS_CLIENTCERTFP) 940 { 941 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_AUTH_FAILED", client, 942 "Link with server $client.details denied: Authentication failed: $auth_failure_msg", 943 log_data_string("auth_failure_msg", "certfp mismatch"), 944 log_data_link_block(link)); 945 } else 946 { 947 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_AUTH_FAILED", client, 948 "Link with server $client.details denied: Authentication failed: $auth_failure_msg", 949 log_data_string("auth_failure_msg", "bad password"), 950 log_data_link_block(link)); 951 } 952 exit_client(client, NULL, "Link denied (Authentication failed)"); 953 return NULL; 954 } 955 956 /* Verify the TLS certificate (if requested) */ 957 if (link->verify_certificate) 958 { 959 char *errstr = NULL; 960 961 if (!IsTLS(client)) 962 { 963 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_VERIFY_CERTIFICATE_FAILED", client, 964 "Link with server $client.details denied: verify-certificate failed: $certificate_failure_msg", 965 log_data_string("certificate_failure_msg", "not using TLS"), 966 log_data_link_block(link)); 967 exit_client(client, NULL, "Link denied (Not using TLS)"); 968 return NULL; 969 } 970 if (!verify_certificate(client->local->ssl, link->servername, &errstr)) 971 { 972 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_VERIFY_CERTIFICATE_FAILED", client, 973 "Link with server $client.details denied: verify-certificate failed: $certificate_failure_msg", 974 log_data_string("certificate_failure_msg", errstr), 975 log_data_link_block(link)); 976 exit_client(client, NULL, "Link denied (Certificate verification failed)"); 977 return NULL; 978 } 979 } 980 981 if ((bconf = find_ban(NULL, client->name, CONF_BAN_SERVER))) 982 { 983 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_SERVER_BAN", client, 984 "Link with server $client.details denied: " 985 "Server is banned ($ban_reason)", 986 log_data_string("ban_reason", bconf->reason), 987 log_data_link_block(link)); 988 exit_client_fmt(client, NULL, "Banned server: %s", bconf->reason); 989 return NULL; 990 } 991 992 if (link->class->clients + 1 > link->class->maxclients) 993 { 994 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_CLASS_FULL", client, 995 "Link with server $client.details denied: " 996 "class '$link_block.class' is full", 997 log_data_link_block(link)); 998 exit_client(client, NULL, "Full class"); 999 return NULL; 1000 } 1001 if (!IsLocalhost(client) && (iConf.plaintext_policy_server == POLICY_DENY) && !IsSecure(client)) 1002 { 1003 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_NO_TLS", client, 1004 "Link with server $client.details denied: " 1005 "Server needs to use TLS (set::plaintext-policy::server is 'deny')\n" 1006 "See https://www.unrealircd.org/docs/FAQ#server-requires-tls", 1007 log_data_link_block(link)); 1008 exit_client(client, NULL, "Servers need to use TLS (set::plaintext-policy::server is 'deny')"); 1009 return NULL; 1010 } 1011 if (IsSecure(client) && (iConf.outdated_tls_policy_server == POLICY_DENY) && outdated_tls_client(client)) 1012 { 1013 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_OUTDATED_TLS", client, 1014 "Link with server $client.details denied: " 1015 "Server is using an outdated TLS protocol or cipher ($tls_cipher) and set::outdated-tls-policy::server is 'deny'.\n" 1016 "See https://www.unrealircd.org/docs/FAQ#server-outdated-tls", 1017 log_data_link_block(link), 1018 log_data_string("tls_cipher", tls_get_cipher(client))); 1019 exit_client(client, NULL, "Server using outdates TLS protocol or cipher (set::outdated-tls-policy::server is 'deny')"); 1020 return NULL; 1021 } 1022 /* This one is at the end, because it causes us to delink another server, 1023 * so we want to be (reasonably) sure that this one will succeed before 1024 * breaking the other one. 1025 */ 1026 if ((acptr = find_server(client->name, NULL))) 1027 { 1028 if (IsMe(acptr)) 1029 { 1030 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_SERVER_EXISTS", client, 1031 "Link with server $client.details denied: " 1032 "Server is trying to link with my name ($me_name)", 1033 log_data_string("me_name", me.name), 1034 log_data_link_block(link)); 1035 exit_client(client, NULL, "Server Exists (server trying to link with same name as myself)"); 1036 return NULL; 1037 } else { 1038 unreal_log(ULOG_ERROR, "link", "LINK_DROPPED_REINTRODUCED", client, 1039 "Link with server $client.details causes older link " 1040 "with same server via $existing_client.server.uplink to be dropped.", 1041 log_data_client("existing_client", acptr), 1042 log_data_link_block(link)); 1043 exit_client_ex(acptr, client->direction, NULL, "Old link dropped, resyncing"); 1044 } 1045 } 1046 1047 return link; 1048 } 1049 1050 /** Server command. Only for locally connected servers!!. 1051 * parv[1] = server name 1052 * parv[2] = hop count 1053 * parv[3] = server description, may include protocol version and other stuff too (VL) 1054 */ 1055 CMD_FUNC(cmd_server) 1056 { 1057 const char *servername = NULL; /* Pointer for servername */ 1058 char *ch = NULL; /* */ 1059 char descbuf[BUFSIZE]; 1060 int hop = 0; 1061 char info[REALLEN + 61]; 1062 ConfigItem_link *aconf = NULL; 1063 char *flags = NULL, *protocol = NULL, *inf = NULL, *num = NULL; 1064 int incoming; 1065 const char *err; 1066 1067 if (IsUser(client)) 1068 { 1069 sendnumeric(client, ERR_ALREADYREGISTRED); 1070 sendnotice(client, "*** Sorry, but your IRC program doesn't appear to support changing servers."); 1071 return; 1072 } 1073 1074 if (parc < 4 || (!*parv[3])) 1075 { 1076 exit_client(client, NULL, "Not enough SERVER parameters"); 1077 return; 1078 } 1079 1080 servername = parv[1]; 1081 1082 /* Remote 'SERVER' command is not possible on a 100% SID network */ 1083 if (!MyConnect(client)) 1084 { 1085 unreal_log(ULOG_ERROR, "link", "LINK_OLD_PROTOCOL", client, 1086 "Server link $client tried to introduce $servername using SERVER command. " 1087 "Server is using an old and unsupported protocol from UnrealIRCd 3.2.x or earlier. " 1088 "See https://www.unrealircd.org/docs/FAQ#old-server-protocol", 1089 log_data_string("servername", servername)); 1090 exit_client(client->direction, NULL, "Introduced another server with unsupported protocol"); 1091 return; 1092 } 1093 1094 if (client->local->listener && (client->local->listener->options & LISTENER_CLIENTSONLY)) 1095 { 1096 exit_client(client, NULL, "This port is for clients only"); 1097 return; 1098 } 1099 1100 if (!valid_server_name(servername)) 1101 { 1102 exit_client(client, NULL, "Bogus server name"); 1103 return; 1104 } 1105 1106 if (!client->local->passwd) 1107 { 1108 exit_client(client, NULL, "Missing password"); 1109 return; 1110 } 1111 1112 /* We set the client->name early here, even though it is not authenticated yet. 1113 * Reason is that it makes the notices and logging more useful. 1114 * This should be safe as it is not in the server linked list yet or hash table. 1115 * CMTSRV941 -- Syzop. 1116 */ 1117 strlcpy(client->name, servername, sizeof(client->name)); 1118 1119 if (!(aconf = verify_link(client))) 1120 return; /* Rejected */ 1121 1122 /* From this point the server is authenticated, so we can be more verbose 1123 * with notices to ircops and in exit_client() and such. 1124 */ 1125 1126 1127 if (strlen(client->id) != 3) 1128 { 1129 unreal_log(ULOG_ERROR, "link", "LINK_OLD_PROTOCOL", client, 1130 "Server link $servername rejected. Server is using an old and unsupported protocol from UnrealIRCd 3.2.x or earlier. " 1131 "See https://www.unrealircd.org/docs/FAQ#old-server-protocol", 1132 log_data_string("servername", servername)); 1133 exit_client(client, NULL, "Server using old unsupported protocol from UnrealIRCd 3.2.x or earlier. " 1134 "See https://www.unrealircd.org/docs/FAQ#old-server-protocol"); 1135 return; 1136 } 1137 1138 hop = atol(parv[2]); 1139 if (hop != 1) 1140 { 1141 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_INVALID_HOPCOUNT", client, 1142 "Server link $servername rejected. Directly linked server provided a hopcount of $hopcount, while 1 was expected.", 1143 log_data_string("servername", servername), 1144 log_data_integer("hopcount", hop)); 1145 exit_client(client, NULL, "Invalid SERVER message, hop count must be 1"); 1146 return; 1147 } 1148 client->hopcount = hop; 1149 1150 strlcpy(info, parv[parc - 1], sizeof(info)); 1151 1152 /* Parse "VL" data in description */ 1153 if (SupportVL(client)) 1154 { 1155 char tmp[REALLEN + 61]; 1156 inf = protocol = flags = num = NULL; 1157 strlcpy(tmp, info, sizeof(tmp)); /* work on a copy */ 1158 1159 /* We are careful here to allow invalid syntax or missing 1160 * stuff, which mean that particular variable will stay NULL. 1161 */ 1162 1163 protocol = strtok(tmp, "-"); 1164 if (protocol) 1165 flags = strtok(NULL, "-"); 1166 if (flags) 1167 num = strtok(NULL, " "); 1168 if (num) 1169 inf = strtok(NULL, ""); 1170 if (inf) 1171 { 1172 strlcpy(client->info, inf[0] ? inf : "server", sizeof(client->info)); /* set real description */ 1173 1174 if (!_check_deny_version(client, NULL, atoi(protocol), flags)) 1175 return; /* Rejected */ 1176 } else { 1177 strlcpy(client->info, info[0] ? info : "server", sizeof(client->info)); 1178 } 1179 } else { 1180 strlcpy(client->info, info[0] ? info : "server", sizeof(client->info)); 1181 } 1182 1183 if ((err = check_deny_link(aconf, 0))) 1184 { 1185 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_DENY_LINK_BLOCK", client, 1186 "Server link $servername rejected by deny link { } block: $reason", 1187 log_data_string("servername", servername), 1188 log_data_string("reason", err)); 1189 exit_client_fmt(client, NULL, "Disallowed by connection rule: %s", err); 1190 return; 1191 } 1192 1193 if (aconf->options & CONNECT_QUARANTINE) 1194 SetQuarantined(client); 1195 1196 ircsnprintf(descbuf, sizeof descbuf, "Server: %s", servername); 1197 fd_desc(client->local->fd, descbuf); 1198 1199 incoming = IsUnknown(client) ? 1 : 0; 1200 1201 if (client->local->passwd) 1202 safe_free(client->local->passwd); 1203 1204 /* Set up server structure */ 1205 free_pending_net(client); 1206 SetServer(client); 1207 irccounts.me_servers++; 1208 irccounts.servers++; 1209 irccounts.unknown--; 1210 list_move(&client->client_node, &global_server_list); 1211 list_move(&client->lclient_node, &lclient_list); 1212 list_add(&client->special_node, &server_list); 1213 1214 if (find_uline(client->name)) 1215 { 1216 if (client->server && client->server->features.software && !strncmp(client->server->features.software, "UnrealIRCd-", 11)) 1217 { 1218 unreal_log(ULOG_ERROR, "link", "BAD_ULINES", client, 1219 "Bad ulines! Server $client matches your ulines { } block, but this server " 1220 "is an UnrealIRCd server. UnrealIRCd servers should never be ulined as it " 1221 "causes security issues. Ulines should only be added for services! " 1222 "See https://www.unrealircd.org/docs/FAQ#bad-ulines."); 1223 exit_client(client, NULL, "Bad ulines. See https://www.unrealircd.org/docs/FAQ#bad-ulines"); 1224 } 1225 SetULine(client); 1226 } 1227 1228 find_or_add(client->name); 1229 1230 if (IsSecure(client)) 1231 { 1232 unreal_log(ULOG_INFO, "link", "SERVER_LINKED", client, 1233 "Server linked: $me -> $client [secure: $tls_cipher]", 1234 log_data_string("tls_cipher", tls_get_cipher(client)), 1235 log_data_client("me", &me)); 1236 tls_link_notification_verify(client, aconf); 1237 } 1238 else 1239 { 1240 unreal_log(ULOG_INFO, "link", "SERVER_LINKED", client, 1241 "Server linked: $me -> $client", 1242 log_data_client("me", &me)); 1243 /* Print out a warning if linking to a non-TLS server unless it's localhost. 1244 * Yeah.. there are still other cases when non-TLS links are fine (eg: local IP 1245 * of the same machine), we won't bother with detecting that. -- Syzop 1246 */ 1247 if (!IsLocalhost(client) && (iConf.plaintext_policy_server == POLICY_WARN)) 1248 { 1249 unreal_log(ULOG_WARNING, "link", "LINK_WARNING_NO_TLS", client, 1250 "Link with server $client.details is unencrypted (not TLS). " 1251 "We highly recommend to use TLS for server linking. " 1252 "See https://www.unrealircd.org/docs/Linking_servers", 1253 log_data_link_block(aconf)); 1254 } 1255 if (IsSecure(client) && (iConf.outdated_tls_policy_server == POLICY_WARN) && outdated_tls_client(client)) 1256 { 1257 unreal_log(ULOG_WARNING, "link", "LINK_WARNING_OUTDATED_TLS", client, 1258 "Link with server $client.details is using an outdated " 1259 "TLS protocol or cipher ($tls_cipher).", 1260 log_data_link_block(aconf), 1261 log_data_string("tls_cipher", tls_get_cipher(client))); 1262 } 1263 } 1264 1265 add_to_client_hash_table(client->name, client); 1266 /* doesnt duplicate client->server if allocted this struct already */ 1267 make_server(client); 1268 client->uplink = &me; 1269 if (!client->server->conf) 1270 client->server->conf = aconf; /* Only set serv->conf to aconf if not set already! Bug #0003913 */ 1271 if (incoming) 1272 client->server->conf->refcount++; 1273 client->server->conf->class->clients++; 1274 client->local->class = client->server->conf->class; 1275 1276 RunHook(HOOKTYPE_SERVER_CONNECT, client); 1277 1278 server_sync(client, aconf, incoming); 1279 } 1280 1281 /** Remote server command (SID). 1282 * parv[1] = server name 1283 * parv[2] = hop count (always >1) 1284 * parv[3] = SID 1285 * parv[4] = server description 1286 */ 1287 CMD_FUNC(cmd_sid) 1288 { 1289 Client *acptr, *ocptr; 1290 ConfigItem_link *aconf; 1291 ConfigItem_ban *bconf; 1292 int hop; 1293 const char *servername = parv[1]; 1294 Client *direction = client->direction; /* lazy, since this function may be removed soon */ 1295 1296 /* Only allow this command from server sockets */ 1297 if (!IsServer(client->direction)) 1298 { 1299 sendnumeric(client, ERR_NOTFORUSERS, "SID"); 1300 return; 1301 } 1302 1303 if (parc < 4 || BadPtr(parv[3])) 1304 { 1305 sendnumeric(client, ERR_NEEDMOREPARAMS, "SID"); 1306 return; 1307 } 1308 1309 /* The SID check is done early because we do all the killing by SID, 1310 * so we want to know if that won't work first. 1311 */ 1312 if (!valid_sid(parv[3])) 1313 { 1314 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_INVALID_SID", client, 1315 "Denied remote server $servername which was introduced by $client: " 1316 "Invalid SID.", 1317 log_data_string("servername", servername), 1318 log_data_string("sid", parv[3])); 1319 /* Since we cannot SQUIT via SID (since it is invalid), this gives 1320 * us huge doubts about the accuracy of the uplink, so in this case 1321 * we terminate the entire uplink. 1322 */ 1323 exit_client(client, NULL, "Trying to introduce a server with an invalid SID"); 1324 return; 1325 } 1326 1327 /* Check if server already exists... */ 1328 if ((acptr = find_server(servername, NULL))) 1329 { 1330 /* Found. Bad. Quit. */ 1331 1332 if (IsMe(acptr)) 1333 { 1334 /* This should never happen, not even due to a race condition. 1335 * We cannot send SQUIT here either since it is unclear what 1336 * side would be squitted. 1337 * As said, not really important, as this does not happen anyway. 1338 */ 1339 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_DUPLICATE_SERVER_IS_ME", client, 1340 "Denied remote server $servername which was introduced by $client: " 1341 "Server is using our servername, this should be impossible!", 1342 log_data_string("servername", servername)); 1343 sendto_one(client, NULL, "ERROR: Server %s exists (it's me!)", me.name); 1344 exit_client(client, NULL, "Server Exists"); 1345 return; 1346 } 1347 1348 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_DUPLICATE_SERVER", client, 1349 "Denied remote server $servername which was introduced by $client: " 1350 "Already linked via $existing_client.server.uplink.", 1351 log_data_string("servername", servername), 1352 log_data_client("existing_client", acptr)); 1353 // FIXME: oldest should die. 1354 // FIXME: code below looks wrong, it checks direction TS instead of anything else 1355 acptr = acptr->direction; 1356 ocptr = (direction->local->creationtime > acptr->local->creationtime) ? acptr : direction; 1357 acptr = (direction->local->creationtime > acptr->local->creationtime) ? direction : acptr; 1358 // FIXME: Wait, this kills entire acptr? Without sending SQUIT even :D 1359 exit_client(acptr, NULL, "Server Exists"); 1360 return; 1361 } 1362 1363 if ((acptr = find_client(parv[3], NULL))) 1364 { 1365 unreal_log(ULOG_ERROR, "link", "LINK_DENIED_DUPLICATE_SID_SERVER", client, 1366 "Denied server $servername with SID $sid: Server with SID $existing_client.id ($existing_client) is already linked.", 1367 log_data_string("servername", servername), 1368 log_data_string("sid", parv[3]), 1369 log_data_client("existing_client", acptr)); 1370 sendto_one(client, NULL, "SQUIT %s :Server with this SID (%s) already exists (%s)", parv[3], parv[3], acptr->name); 1371 return; 1372 } 1373 1374 /* Check deny server { } */ 1375 if ((bconf = find_ban(NULL, servername, CONF_BAN_SERVER))) 1376 { 1377 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_SERVER_BAN", client, 1378 "Denied remote server $servername which was introduced by $client: " 1379 "Server is banned ($ban_reason)", 1380 log_data_string("servername", servername), 1381 log_data_string("ban_reason", bconf->reason)); 1382 /* Before UnrealIRCd 6 this would SQUIT the server who introduced 1383 * this server. That seems a bit of an overreaction, so we now 1384 * send a SQUIT instead. 1385 */ 1386 sendto_one(client, NULL, "SQUIT %s :Banned server: %s", parv[3], bconf->reason); 1387 return; 1388 } 1389 1390 /* OK, let us check the data now */ 1391 if (!valid_server_name(servername)) 1392 { 1393 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_INVALID_SERVERNAME", client, 1394 "Denied remote server $servername which was introduced by $client: " 1395 "Invalid server name.", 1396 log_data_string("servername", servername)); 1397 sendto_one(client, NULL, "SQUIT %s :Invalid servername", parv[3]); 1398 return; 1399 } 1400 1401 hop = atoi(parv[2]); 1402 if (hop < 2) 1403 { 1404 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_INVALID_HOP_COUNT", client, 1405 "Denied remote server $servername which was introduced by $client: " 1406 "Invalid server name.", 1407 log_data_string("servername", servername), 1408 log_data_integer("hop_count", hop)); 1409 sendto_one(client, NULL, "SQUIT %s :Invalid hop count (%d)", parv[3], hop); 1410 return; 1411 } 1412 1413 if (!client->direction->server->conf) 1414 { 1415 unreal_log(ULOG_ERROR, "link", "BUG_LOST_CONFIG", client, 1416 "[BUG] Lost link conf record for link $direction.", 1417 log_data_client("direction", direction)); 1418 exit_client(client->direction, NULL, "BUG: lost link configuration"); 1419 return; 1420 } 1421 1422 aconf = client->direction->server->conf; 1423 1424 if (!aconf->hub) 1425 { 1426 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_NO_HUB", client, 1427 "Denied remote server $servername which was introduced by $client: " 1428 "Server may not introduce this server ($direction is not a hub).", 1429 log_data_string("servername", servername), 1430 log_data_client("direction", client->direction)); 1431 sendto_one(client, NULL, "SQUIT %s :Server is not permitted to be a hub: %s", 1432 parv[3], client->direction->name); 1433 return; 1434 } 1435 1436 if (!match_simple(aconf->hub, servername)) 1437 { 1438 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_NO_MATCHING_HUB", client, 1439 "Denied remote server $servername which was introduced by $client: " 1440 "Server may not introduce this server ($direction hubmask does not allow it).", 1441 log_data_string("servername", servername), 1442 log_data_client("direction", client->direction)); 1443 sendto_one(client, NULL, "SQUIT %s :Hub config for %s does not allow introducing this server", 1444 parv[3], client->direction->name); 1445 return; 1446 } 1447 1448 if (aconf->leaf) 1449 { 1450 if (!match_simple(aconf->leaf, servername)) 1451 { 1452 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_NO_MATCHING_LEAF", client, 1453 "Denied remote server $servername which was introduced by $client: " 1454 "Server may not introduce this server ($direction leaf config does not allow it).", 1455 log_data_string("servername", servername), 1456 log_data_client("direction", client->direction)); 1457 sendto_one(client, NULL, "SQUIT %s :Leaf config for %s does not allow introducing this server", 1458 parv[3], client->direction->name); 1459 return; 1460 } 1461 } 1462 1463 if (aconf->leaf_depth && (hop > aconf->leaf_depth)) 1464 { 1465 unreal_log(ULOG_ERROR, "link", "REMOTE_LINK_DENIED_LEAF_DEPTH", client, 1466 "Denied remote server $servername which was introduced by $client: " 1467 "Server may not introduce this server ($direction leaf depth config does not allow it).", 1468 log_data_string("servername", servername), 1469 log_data_client("direction", client->direction)); 1470 sendto_one(client, NULL, "SQUIT %s :Leaf depth config for %s does not allow introducing this server", 1471 parv[3], client->direction->name); 1472 return; 1473 } 1474 1475 /* All approved, add the server */ 1476 acptr = make_client(direction, find_server(client->name, direction)); 1477 strlcpy(acptr->name, servername, sizeof(acptr->name)); 1478 acptr->hopcount = hop; 1479 strlcpy(acptr->id, parv[3], sizeof(acptr->id)); 1480 strlcpy(acptr->info, parv[parc - 1], sizeof(acptr->info)); 1481 make_server(acptr); 1482 SetServer(acptr); 1483 /* If this server is U-lined, or the parent is, then mark it as U-lined */ 1484 if (IsULine(client) || find_uline(acptr->name)) 1485 SetULine(acptr); 1486 irccounts.servers++; 1487 find_or_add(acptr->name); 1488 add_client_to_list(acptr); 1489 add_to_client_hash_table(acptr->name, acptr); 1490 add_to_id_hash_table(acptr->id, acptr); 1491 list_move(&acptr->client_node, &global_server_list); 1492 1493 if (IsULine(client->direction) || IsSynched(client->direction)) 1494 { 1495 /* Log these (but don't show when still syncing) */ 1496 unreal_log(ULOG_INFO, "link", "SERVER_LINKED_REMOTE", acptr, 1497 "Server linked: $client -> $other_server", 1498 log_data_client("other_server", client)); 1499 } 1500 1501 RunHook(HOOKTYPE_SERVER_CONNECT, acptr); 1502 1503 sendto_server(client, 0, 0, NULL, ":%s SID %s %d %s :%s", 1504 acptr->uplink->id, acptr->name, hop + 1, acptr->id, acptr->info); 1505 1506 RunHook(HOOKTYPE_POST_SERVER_CONNECT, acptr); 1507 } 1508 1509 void _introduce_user(Client *to, Client *acptr) 1510 { 1511 char buf[512]; 1512 1513 build_umode_string(acptr, 0, SEND_UMODES, buf); 1514 1515 sendto_one_nickcmd(to, NULL, acptr, buf); 1516 1517 send_moddata_client(to, acptr); 1518 1519 if (acptr->user->away) 1520 sendto_one(to, NULL, ":%s AWAY :%s", acptr->id, acptr->user->away); 1521 1522 if (acptr->user->swhois) 1523 { 1524 SWhois *s; 1525 for (s = acptr->user->swhois; s; s = s->next) 1526 { 1527 if (CHECKSERVERPROTO(to, PROTO_EXTSWHOIS)) 1528 { 1529 sendto_one(to, NULL, ":%s SWHOIS %s + %s %d :%s", 1530 me.id, acptr->name, s->setby, s->priority, s->line); 1531 } else 1532 { 1533 sendto_one(to, NULL, ":%s SWHOIS %s :%s", 1534 me.id, acptr->name, s->line); 1535 } 1536 } 1537 } 1538 } 1539 1540 #define SafeStr(x) ((x && *(x)) ? (x) : "*") 1541 1542 /** Broadcast SINFO. 1543 * @param cptr The server to send the information about. 1544 * @param to The server to send the information TO (NULL for broadcast). 1545 * @param except The direction NOT to send to. 1546 * This function takes into account that the server may not 1547 * provide all of the detailed info. If any information is 1548 * absent we will send 0 for numbers and * for NULL strings. 1549 */ 1550 void _broadcast_sinfo(Client *acptr, Client *to, Client *except) 1551 { 1552 char chanmodes[128], buf[512]; 1553 1554 if (acptr->server->features.chanmodes[0]) 1555 { 1556 snprintf(chanmodes, sizeof(chanmodes), "%s,%s,%s,%s", 1557 acptr->server->features.chanmodes[0], 1558 acptr->server->features.chanmodes[1], 1559 acptr->server->features.chanmodes[2], 1560 acptr->server->features.chanmodes[3]); 1561 } else { 1562 strlcpy(chanmodes, "*", sizeof(chanmodes)); 1563 } 1564 1565 snprintf(buf, sizeof(buf), "%lld %d %s %s %s :%s", 1566 (long long)acptr->server->boottime, 1567 acptr->server->features.protocol, 1568 SafeStr(acptr->server->features.usermodes), 1569 chanmodes, 1570 SafeStr(acptr->server->features.nickchars), 1571 SafeStr(acptr->server->features.software)); 1572 1573 if (to) 1574 { 1575 /* Targetted to one server */ 1576 sendto_one(to, NULL, ":%s SINFO %s", acptr->id, buf); 1577 } else { 1578 /* Broadcast (except one side...) */ 1579 sendto_server(except, 0, 0, NULL, ":%s SINFO %s", acptr->id, buf); 1580 } 1581 } 1582 1583 /** Sync all information with server 'client'. 1584 * Eg: users, channels, everything. 1585 * @param client The newly linked in server 1586 * @param aconf The link block that belongs to this server 1587 * @note This function (via cmd_server) is called from both sides, so 1588 * from the incoming side and the outgoing side. 1589 */ 1590 int server_sync(Client *client, ConfigItem_link *aconf, int incoming) 1591 { 1592 Client *acptr; 1593 1594 if (incoming) 1595 { 1596 /* If this is an incomming connection, then we have just received 1597 * their stuff and now send our PASS, PROTOCTL and SERVER messages back. 1598 */ 1599 if (!IsEAuth(client)) /* if eauth'd then we already sent the passwd */ 1600 sendto_one(client, NULL, "PASS :%s", (aconf->auth->type == AUTHTYPE_PLAINTEXT) ? aconf->auth->data : "*"); 1601 1602 send_proto(client, aconf); 1603 send_server_message(client); 1604 } 1605 1606 /* Broadcast new server to the rest of the network */ 1607 sendto_server(client, 0, 0, NULL, ":%s SID %s 2 %s :%s", 1608 client->uplink->id, client->name, client->id, client->info); 1609 1610 /* Broadcast the just-linked-in featureset to other servers on our side */ 1611 broadcast_sinfo(client, NULL, client); 1612 1613 /* Send moddata of &me (if any, likely minimal) */ 1614 send_moddata_client(client, &me); 1615 1616 list_for_each_entry_reverse(acptr, &global_server_list, client_node) 1617 { 1618 /* acptr->direction == acptr for acptr == client */ 1619 if (acptr->direction == client) 1620 continue; 1621 1622 if (IsServer(acptr)) 1623 { 1624 sendto_one(client, NULL, ":%s SID %s %d %s :%s", 1625 acptr->uplink->id, 1626 acptr->name, acptr->hopcount + 1, 1627 acptr->id, acptr->info); 1628 1629 /* Also signal to the just-linked server which 1630 * servers are fully linked. 1631 * Now you might ask yourself "Why don't we just 1632 * assume every server you get during link phase 1633 * is fully linked?", well.. there's a race condition 1634 * if 2 servers link (almost) at the same time, 1635 * then you would think the other one is fully linked 1636 * while in fact he was not.. -- Syzop. 1637 */ 1638 if (acptr->server->flags.synced) 1639 sendto_one(client, NULL, ":%s EOS", acptr->id); 1640 /* Send SINFO of our servers to their side */ 1641 broadcast_sinfo(acptr, client, NULL); 1642 send_moddata_client(client, acptr); /* send moddata of server 'acptr' (if any, likely minimal) */ 1643 } 1644 } 1645 1646 /* Synching nick information */ 1647 list_for_each_entry_reverse(acptr, &client_list, client_node) 1648 { 1649 /* acptr->direction == acptr for acptr == client */ 1650 if (acptr->direction == client) 1651 continue; 1652 if (IsUser(acptr)) 1653 introduce_user(client, acptr); 1654 } 1655 /* 1656 ** Last, pass all channels plus statuses 1657 */ 1658 { 1659 Channel *channel; 1660 for (channel = channels; channel; channel = channel->nextch) 1661 { 1662 send_channel_modes_sjoin3(client, channel); 1663 if (channel->topic_time) 1664 sendto_one(client, NULL, "TOPIC %s %s %lld :%s", 1665 channel->name, channel->topic_nick, 1666 (long long)channel->topic_time, channel->topic); 1667 send_moddata_channel(client, channel); 1668 } 1669 } 1670 1671 /* Send ModData for all member(ship) structs */ 1672 send_moddata_members(client); 1673 1674 /* pass on TKLs */ 1675 tkl_sync(client); 1676 1677 RunHook(HOOKTYPE_SERVER_SYNC, client); 1678 1679 sendto_one(client, NULL, "NETINFO %i %lld %i %s 0 0 0 :%s", 1680 irccounts.global_max, (long long)TStime(), UnrealProtocol, 1681 CLOAK_KEY_CHECKSUM, 1682 NETWORK_NAME); 1683 1684 /* Send EOS (End Of Sync) to the just linked server... */ 1685 sendto_one(client, NULL, ":%s EOS", me.id); 1686 RunHook(HOOKTYPE_POST_SERVER_CONNECT, client); 1687 return 0; 1688 } 1689 1690 void tls_link_notification_verify(Client *client, ConfigItem_link *aconf) 1691 { 1692 const char *spki_fp; 1693 const char *tls_fp; 1694 char *errstr = NULL; 1695 int verify_ok; 1696 1697 if (!MyConnect(client) || !client->local->ssl || !aconf) 1698 return; 1699 1700 if ((aconf->auth->type == AUTHTYPE_TLS_CLIENTCERT) || 1701 (aconf->auth->type == AUTHTYPE_TLS_CLIENTCERTFP) || 1702 (aconf->auth->type == AUTHTYPE_SPKIFP)) 1703 { 1704 /* Link verified by certificate or SPKI */ 1705 return; 1706 } 1707 1708 if (aconf->verify_certificate) 1709 { 1710 /* Link verified by trust chain */ 1711 return; 1712 } 1713 1714 tls_fp = moddata_client_get(client, "certfp"); 1715 spki_fp = spki_fingerprint(client); 1716 if (!tls_fp || !spki_fp) 1717 return; /* wtf ? */ 1718 1719 /* Only bother the user if we are linking to UnrealIRCd 4.0.16+, 1720 * since only for these versions we can give precise instructions. 1721 */ 1722 if (!client->server || client->server->features.protocol < 4016) 1723 return; 1724 1725 1726 verify_ok = verify_certificate(client->local->ssl, aconf->servername, &errstr); 1727 if (errstr && strstr(errstr, "not valid for hostname")) 1728 { 1729 unreal_log(ULOG_INFO, "link", "HINT_VERIFY_LINK", client, 1730 "You may want to consider verifying this server link.\n" 1731 "More information about this can be found on https://www.unrealircd.org/Link_verification\n" 1732 "Unfortunately the certificate of server '$client' has a name mismatch:\n" 1733 "$tls_verify_error\n" 1734 "This isn't a fatal error but it will prevent you from using verify-certificate yes;", 1735 log_data_link_block(aconf), 1736 log_data_string("tls_verify_error", errstr)); 1737 } else 1738 if (!verify_ok) 1739 { 1740 unreal_log(ULOG_INFO, "link", "HINT_VERIFY_LINK", client, 1741 "You may want to consider verifying this server link.\n" 1742 "More information about this can be found on https://www.unrealircd.org/Link_verification\n" 1743 "In short: in the configuration file, change the 'link $client {' block to use this as a password:\n" 1744 "password \"$spki_fingerprint\" { spkifp; };\n" 1745 "And follow the instructions on the other side of the link as well (which will be similar, but will use a different hash)", 1746 log_data_link_block(aconf), 1747 log_data_string("spki_fingerprint", spki_fp)); 1748 } else 1749 { 1750 unreal_log(ULOG_INFO, "link", "HINT_VERIFY_LINK", client, 1751 "You may want to consider verifying this server link.\n" 1752 "More information about this can be found on https://www.unrealircd.org/Link_verification\n" 1753 "In short: in the configuration file, add the following to your 'link $client {' block:\n" 1754 "verify-certificate yes;\n" 1755 "Alternatively, you could use SPKI fingerprint verification. Then change the password in the link block to be:\n" 1756 "password \"$spki_fingerprint\" { spki_fp; };", 1757 log_data_link_block(aconf), 1758 log_data_string("spki_fingerprint", spki_fp)); 1759 } 1760 } 1761 1762 /** This will send "to" a full list of the modes for channel channel, 1763 * 1764 * Half of it recoded by Syzop: the whole buffering and size checking stuff 1765 * looked weird and just plain inefficient. We now fill up our send-buffer 1766 * really as much as we can, without causing any overflows of course. 1767 */ 1768 void send_channel_modes_sjoin3(Client *to, Channel *channel) 1769 { 1770 MessageTag *mtags = NULL; 1771 Member *members; 1772 Member *lp; 1773 Ban *ban; 1774 short nomode, nopara; 1775 char tbuf[512]; /* work buffer, for temporary data */ 1776 char buf[1024]; /* send buffer */ 1777 char *bufptr; /* points somewhere in 'buf' */ 1778 char *p; /* points to somewhere in 'tbuf' */ 1779 int prebuflen = 0; /* points to after the <sjointoken> <TS> <chan> <fixmodes> <fixparas <..>> : part */ 1780 int sent = 0; /* we need this so we send at least 1 message about the channel (eg if +P and no members, no bans, #4459) */ 1781 char modebuf[BUFSIZE], parabuf[BUFSIZE]; 1782 1783 if (*channel->name != '#') 1784 return; 1785 1786 nomode = 0; 1787 nopara = 0; 1788 members = channel->members; 1789 1790 /* First we'll send channel, channel modes and members and status */ 1791 1792 *modebuf = *parabuf = '\0'; 1793 channel_modes(to, modebuf, parabuf, sizeof(modebuf), sizeof(parabuf), channel, 1); 1794 1795 /* Strip final space if needed */ 1796 if (*parabuf && (parabuf[strlen(parabuf)-1] == ' ')) 1797 parabuf[strlen(parabuf)-1] = '\0'; 1798 1799 if (!modebuf[1]) 1800 nomode = 1; 1801 if (!(*parabuf)) 1802 nopara = 1; 1803 1804 /* Generate a new message (including msgid). 1805 * Due to the way SJOIN works, we will use the same msgid for 1806 * multiple SJOIN messages to servers. Rest assured that clients 1807 * will never see these duplicate msgid's though. They 1808 * will see a 'special' version instead with a suffix. 1809 */ 1810 new_message(&me, NULL, &mtags); 1811 1812 if (nomode && nopara) 1813 { 1814 ircsnprintf(buf, sizeof(buf), 1815 ":%s SJOIN %lld %s :", me.id, 1816 (long long)channel->creationtime, channel->name); 1817 } 1818 if (nopara && !nomode) 1819 { 1820 ircsnprintf(buf, sizeof(buf), 1821 ":%s SJOIN %lld %s %s :", me.id, 1822 (long long)channel->creationtime, channel->name, modebuf); 1823 } 1824 if (!nopara && !nomode) 1825 { 1826 ircsnprintf(buf, sizeof(buf), 1827 ":%s SJOIN %lld %s %s %s :", me.id, 1828 (long long)channel->creationtime, channel->name, modebuf, parabuf); 1829 } 1830 1831 prebuflen = strlen(buf); 1832 bufptr = buf + prebuflen; 1833 1834 /* RULES: 1835 * - Use 'tbuf' as a working buffer, use 'p' to advance in 'tbuf'. 1836 * Thus, be sure to do a 'p = tbuf' at the top of the loop. 1837 * - When one entry has been build, check if strlen(buf) + strlen(tbuf) > BUFSIZE - 8, 1838 * if so, do not concat but send the current result (buf) first to the server 1839 * and reset 'buf' to only the prebuf part (all until the ':'). 1840 * Then, in both cases, concat 'tbuf' to 'buf' and continue 1841 * - Be sure to ALWAYS zero terminate (*p = '\0') when the entry has been build. 1842 * - Be sure to add a space after each entry ;) 1843 * 1844 * For a more illustrated view, take a look at the first for loop, the others 1845 * are pretty much the same. 1846 * 1847 * Follow these rules, and things would be smooth and efficient (network-wise), 1848 * if you ignore them, expect crashes and/or heap corruption, aka: HELL. 1849 * You have been warned. 1850 * 1851 * Side note: of course things would be more efficient if the prebuf thing would 1852 * not be sent every time, but that's another story 1853 * -- Syzop 1854 */ 1855 1856 for (lp = members; lp; lp = lp->next) 1857 { 1858 p = mystpcpy(tbuf, modes_to_sjoin_prefix(lp->member_modes)); /* eg @+ */ 1859 p = mystpcpy(p, lp->client->id); /* nick (well, id) */ 1860 *p++ = ' '; 1861 *p = '\0'; 1862 1863 /* this is: if (strlen(tbuf) + strlen(buf) > BUFSIZE - 8) */ 1864 if ((p - tbuf) + (bufptr - buf) > BUFSIZE - 8) 1865 { 1866 /* Would overflow, so send our current stuff right now (except new stuff) */ 1867 sendto_one(to, mtags, "%s", buf); 1868 sent++; 1869 ircsnprintf(buf, sizeof(buf), 1870 ":%s SJOIN %lld %s :", me.id, 1871 (long long)channel->creationtime, channel->name); 1872 prebuflen = strlen(buf); 1873 bufptr = buf + prebuflen; 1874 *bufptr = '\0'; 1875 } 1876 /* concat our stuff.. */ 1877 bufptr = mystpcpy(bufptr, tbuf); 1878 } 1879 1880 for (ban = channel->banlist; ban; ban = ban->next) 1881 { 1882 p = tbuf; 1883 if (SupportSJSBY(to)) 1884 p += add_sjsby(p, ban->who, ban->when); 1885 *p++ = '&'; 1886 p = mystpcpy(p, ban->banstr); 1887 *p++ = ' '; 1888 *p = '\0'; 1889 1890 /* this is: if (strlen(tbuf) + strlen(buf) > BUFSIZE - 8) */ 1891 if ((p - tbuf) + (bufptr - buf) > BUFSIZE - 8) 1892 { 1893 /* Would overflow, so send our current stuff right now (except new stuff) */ 1894 sendto_one(to, mtags, "%s", buf); 1895 sent++; 1896 ircsnprintf(buf, sizeof(buf), 1897 ":%s SJOIN %lld %s :", me.id, 1898 (long long)channel->creationtime, channel->name); 1899 prebuflen = strlen(buf); 1900 bufptr = buf + prebuflen; 1901 *bufptr = '\0'; 1902 } 1903 /* concat our stuff.. */ 1904 bufptr = mystpcpy(bufptr, tbuf); 1905 } 1906 1907 for (ban = channel->exlist; ban; ban = ban->next) 1908 { 1909 p = tbuf; 1910 if (SupportSJSBY(to)) 1911 p += add_sjsby(p, ban->who, ban->when); 1912 *p++ = '"'; 1913 p = mystpcpy(p, ban->banstr); 1914 *p++ = ' '; 1915 *p = '\0'; 1916 1917 /* this is: if (strlen(tbuf) + strlen(buf) > BUFSIZE - 8) */ 1918 if ((p - tbuf) + (bufptr - buf) > BUFSIZE - 8) 1919 { 1920 /* Would overflow, so send our current stuff right now (except new stuff) */ 1921 sendto_one(to, mtags, "%s", buf); 1922 sent++; 1923 ircsnprintf(buf, sizeof(buf), 1924 ":%s SJOIN %lld %s :", me.id, 1925 (long long)channel->creationtime, channel->name); 1926 prebuflen = strlen(buf); 1927 bufptr = buf + prebuflen; 1928 *bufptr = '\0'; 1929 } 1930 /* concat our stuff.. */ 1931 bufptr = mystpcpy(bufptr, tbuf); 1932 } 1933 1934 for (ban = channel->invexlist; ban; ban = ban->next) 1935 { 1936 p = tbuf; 1937 if (SupportSJSBY(to)) 1938 p += add_sjsby(p, ban->who, ban->when); 1939 *p++ = '\''; 1940 p = mystpcpy(p, ban->banstr); 1941 *p++ = ' '; 1942 *p = '\0'; 1943 1944 /* this is: if (strlen(tbuf) + strlen(buf) > BUFSIZE - 8) */ 1945 if ((p - tbuf) + (bufptr - buf) > BUFSIZE - 8) 1946 { 1947 /* Would overflow, so send our current stuff right now (except new stuff) */ 1948 sendto_one(to, mtags, "%s", buf); 1949 sent++; 1950 ircsnprintf(buf, sizeof(buf), 1951 ":%s SJOIN %lld %s :", me.id, 1952 (long long)channel->creationtime, channel->name); 1953 prebuflen = strlen(buf); 1954 bufptr = buf + prebuflen; 1955 *bufptr = '\0'; 1956 } 1957 /* concat our stuff.. */ 1958 bufptr = mystpcpy(bufptr, tbuf); 1959 } 1960 1961 if (buf[prebuflen] || !sent) 1962 sendto_one(to, mtags, "%s", buf); 1963 1964 free_message_tags(mtags); 1965 } 1966 1967 void server_generic_free(ModData *m) 1968 { 1969 safe_free(m->ptr); 1970 } 1971 1972 int server_post_connect(Client *client) { 1973 if (cfg.autoconnect_strategy == AUTOCONNECT_SEQUENTIAL_FALLBACK && last_autoconnect_server 1974 && !strcmp(last_autoconnect_server, client->name)) 1975 { 1976 last_autoconnect_server = NULL; 1977 } 1978 return 0; 1979 } 1980 1981 /** Start an outgoing connection to a server, for server linking. 1982 * @param aconf Configuration attached to this server 1983 * @param by The user initiating the connection (can be NULL) 1984 * @param hp The address to connect to. 1985 */ 1986 void _connect_server(ConfigItem_link *aconf, Client *by, struct hostent *hp) 1987 { 1988 Client *client; 1989 1990 if (!aconf->outgoing.hostname && !aconf->outgoing.file) 1991 { 1992 /* Actually the caller should make sure that this doesn't happen, 1993 * so this error may never be triggered: 1994 */ 1995 unreal_log(ULOG_ERROR, "link", "LINK_ERROR_NO_OUTGOING", NULL, 1996 "Connect to $link_block failed: link block is for incoming only (no link::outgoing::hostname or link::outgoing::file set)", 1997 log_data_link_block(aconf)); 1998 return; 1999 } 2000 2001 if (!hp) 2002 { 2003 /* Remove "cache" */ 2004 safe_free(aconf->connect_ip); 2005 } 2006 /* 2007 * If we dont know the IP# for this host and itis a hostname and 2008 * not a ip# string, then try and find the appropriate host record. 2009 */ 2010 if (!aconf->connect_ip && !aconf->outgoing.file) 2011 { 2012 if (is_valid_ip(aconf->outgoing.hostname)) 2013 { 2014 /* link::outgoing::hostname is an IP address. No need to resolve host. */ 2015 safe_strdup(aconf->connect_ip, aconf->outgoing.hostname); 2016 } else 2017 { 2018 /* It's a hostname, let the resolver look it up. */ 2019 int ipv4_explicit_bind = 0; 2020 2021 if (aconf->outgoing.bind_ip && (is_valid_ip(aconf->outgoing.bind_ip) == 4)) 2022 ipv4_explicit_bind = 1; 2023 2024 /* We need this 'aconf->refcount++' or else there's a race condition between 2025 * starting resolving the host and the result of the resolver (we could 2026 * REHASH in that timeframe) leading to an invalid (freed!) 'aconf'. 2027 * -- Syzop, bug #0003689. 2028 */ 2029 aconf->refcount++; 2030 unrealdns_gethostbyname_link(aconf->outgoing.hostname, aconf, ipv4_explicit_bind); 2031 unreal_log(ULOG_INFO, "link", "LINK_RESOLVING", NULL, 2032 "Resolving hostname $link_block.hostname...", 2033 log_data_link_block(aconf)); 2034 /* Going to resolve the hostname, in the meantime we return (asynchronous operation) */ 2035 return; 2036 } 2037 } 2038 client = make_client(NULL, &me); 2039 client->local->hostp = hp; 2040 /* 2041 * Copy these in so we have something for error detection. 2042 */ 2043 strlcpy(client->name, aconf->servername, sizeof(client->name)); 2044 strlcpy(client->local->sockhost, aconf->outgoing.hostname ? aconf->outgoing.hostname : aconf->outgoing.file, HOSTLEN + 1); 2045 2046 if (!connect_server_helper(aconf, client)) 2047 { 2048 fd_close(client->local->fd); 2049 --OpenFiles; 2050 client->local->fd = -2; 2051 free_client(client); 2052 /* Fatal error */ 2053 return; 2054 } 2055 /* The socket has been connected or connect is in progress. */ 2056 make_server(client); 2057 client->server->conf = aconf; 2058 client->server->conf->refcount++; 2059 if (by && IsUser(by)) 2060 strlcpy(client->server->by, by->name, sizeof(client->server->by)); 2061 else 2062 strlcpy(client->server->by, "AutoConn.", sizeof client->server->by); 2063 SetConnecting(client); 2064 SetOutgoing(client); 2065 irccounts.unknown++; 2066 list_add(&client->lclient_node, &unknown_list); 2067 set_sockhost(client, aconf->outgoing.hostname ? aconf->outgoing.hostname : "127.0.0.1"); 2068 add_client_to_list(client); 2069 2070 if (aconf->outgoing.options & CONNECT_TLS) 2071 { 2072 SetTLSConnectHandshake(client); 2073 fd_setselect(client->local->fd, FD_SELECT_WRITE, unreal_tls_client_handshake, client); 2074 } 2075 else 2076 fd_setselect(client->local->fd, FD_SELECT_WRITE, completed_connection, client); 2077 2078 unreal_log(ULOG_INFO, "link", "LINK_CONNECTING", client, 2079 aconf->outgoing.file 2080 ? "Trying to activate link with server $client ($link_block.file)..." 2081 : "Trying to activate link with server $client ($link_block.ip:$link_block.port)...", 2082 log_data_link_block(aconf)); 2083 } 2084 2085 /** Helper function for connect_server() to prepare the actual bind()'ing and connect(). 2086 * This will also take care of logging/sending error messages. 2087 * @param aconf Configuration entry of the server. 2088 * @param client The client entry that we will use and fill in. 2089 * @returns 1 on success, 0 on failure. 2090 */ 2091 static int connect_server_helper(ConfigItem_link *aconf, Client *client) 2092 { 2093 char *bindip; 2094 char buf[BUFSIZE]; 2095 2096 if (!aconf->connect_ip && !aconf->outgoing.file) 2097 { 2098 unreal_log(ULOG_ERROR, "link", "LINK_ERROR_NOIP", client, 2099 "Connect to $client failed: no IP address or file to connect to", 2100 log_data_link_block(aconf)); 2101 return 0; /* handled upstream or shouldn't happen */ 2102 } 2103 2104 if (aconf->outgoing.file) 2105 SetUnixSocket(client); 2106 else if (strchr(aconf->connect_ip, ':')) 2107 SetIPV6(client); 2108 2109 safe_strdup(client->ip, aconf->connect_ip ? aconf->connect_ip : "127.0.0.1"); 2110 2111 snprintf(buf, sizeof buf, "Outgoing connection: %s", get_client_name(client, TRUE)); 2112 client->local->fd = fd_socket(IsUnixSocket(client) ? AF_UNIX : (IsIPV6(client) ? AF_INET6 : AF_INET), SOCK_STREAM, 0, buf); 2113 if (client->local->fd < 0) 2114 { 2115 if (ERRNO == P_EMFILE) 2116 { 2117 unreal_log(ULOG_ERROR, "link", "LINK_ERROR_MAXCLIENTS", client, 2118 "Connect to $client failed: no more sockets available", 2119 log_data_link_block(aconf)); 2120 return 0; 2121 } 2122 unreal_log(ULOG_ERROR, "link", "LINK_ERROR_SOCKET", client, 2123 "Connect to $client failed: could not create socket: $socket_error", 2124 log_data_socket_error(-1), 2125 log_data_link_block(aconf)); 2126 return 0; 2127 } 2128 if (++OpenFiles >= maxclients) 2129 { 2130 unreal_log(ULOG_ERROR, "link", "LINK_ERROR_MAXCLIENTS", client, 2131 "Connect to $client failed: no more connections available", 2132 log_data_link_block(aconf)); 2133 return 0; 2134 } 2135 2136 set_sockhost(client, aconf->outgoing.hostname ? aconf->outgoing.hostname : "127.0.0.1"); 2137 2138 if (!aconf->outgoing.bind_ip && iConf.link_bindip) 2139 bindip = iConf.link_bindip; 2140 else 2141 bindip = aconf->outgoing.bind_ip; 2142 2143 if (bindip && strcmp("*", bindip)) 2144 { 2145 if (!unreal_bind(client->local->fd, bindip, 0, IsIPV6(client))) 2146 { 2147 unreal_log(ULOG_ERROR, "link", "LINK_ERROR_SOCKET_BIND", client, 2148 "Connect to $client failed: could not bind socket to $link_block.bind_ip: $socket_error -- " 2149 "Your link::outgoing::bind-ip is probably incorrect.", 2150 log_data_socket_error(client->local->fd), 2151 log_data_link_block(aconf)); 2152 return 0; 2153 } 2154 } 2155 2156 set_sock_opts(client->local->fd, client, IsIPV6(client)); 2157 2158 if (!unreal_connect(client->local->fd, 2159 aconf->outgoing.file ? aconf->outgoing.file : client->ip, 2160 aconf->outgoing.port, client->local->socket_type)) 2161 { 2162 unreal_log(ULOG_ERROR, "link", "LINK_ERROR_CONNECT", client, 2163 aconf->outgoing.file 2164 ? "Connect to $client ($link_block.file) failed: $socket_error" 2165 : "Connect to $client ($link_block.ip:$link_block.port) failed: $socket_error", 2166 log_data_socket_error(client->local->fd), 2167 log_data_link_block(aconf)); 2168 return 0; 2169 } 2170 2171 return 1; 2172 } 2173 2174 int _is_services_but_not_ulined(Client *client) 2175 { 2176 if (!client->server || !client->server->features.software || !*client->name) 2177 return 0; /* cannot detect software version or name not available yet */ 2178 2179 if (our_strcasestr(client->server->features.software, "anope") || 2180 our_strcasestr(client->server->features.software, "atheme")) 2181 { 2182 if (!find_uline(client->name)) 2183 { 2184 unreal_log(ULOG_ERROR, "link", "LINK_NO_ULINES", client, 2185 "Server $client is a services server ($software). " 2186 "However, server $me does not have $client in the ulines { } block, " 2187 "which is required for services servers. " 2188 "See https://www.unrealircd.org/docs/Ulines_block", 2189 log_data_client("me", &me), 2190 log_data_string("software", client->server->features.software)); 2191 return 1; /* Is services AND no ulines { } entry */ 2192 } 2193 } 2194 return 0; 2195 } 2196 2197 /** Check if this link should be denied due to deny link { } configuration 2198 * @param link The link block 2199 * @param auto_connect Set this to 1 if this is called from auto connect code 2200 * (it will then check both CRULE_AUTO + CRULE_ALL) 2201 * set it to 0 otherwise (will not check CRULE_AUTO blocks). 2202 * @returns The deny block if the server should be denied, or NULL if no deny block. 2203 */ 2204 const char *_check_deny_link(ConfigItem_link *link, int auto_connect) 2205 { 2206 ConfigItem_deny_link *d; 2207 2208 for (d = conf_deny_link; d; d = d->next) 2209 { 2210 if ((auto_connect == 0) && (d->flag.type == CRULE_AUTO)) 2211 continue; 2212 if (unreal_mask_match_string(link->servername, d->mask) && 2213 crule_eval(d->rule)) 2214 { 2215 return d->reason; 2216 } 2217 } 2218 return NULL; 2219 } 2220 2221 int server_stats_denylink_all(Client *client, const char *para) 2222 { 2223 ConfigItem_deny_link *links; 2224 ConfigItem_mask *m; 2225 2226 if (!para || !(!strcmp(para, "D") || !strcasecmp(para, "denylinkall"))) 2227 return 0; 2228 2229 for (links = conf_deny_link; links; links = links->next) 2230 { 2231 if (links->flag.type == CRULE_ALL) 2232 { 2233 for (m = links->mask; m; m = m->next) 2234 sendnumeric(client, RPL_STATSDLINE, 'D', m->mask, links->prettyrule); 2235 } 2236 } 2237 2238 return 1; 2239 } 2240 2241 int server_stats_denylink_auto(Client *client, const char *para) 2242 { 2243 ConfigItem_deny_link *links; 2244 ConfigItem_mask *m; 2245 2246 if (!para || !(!strcmp(para, "d") || !strcasecmp(para, "denylinkauto"))) 2247 return 0; 2248 2249 for (links = conf_deny_link; links; links = links->next) 2250 { 2251 if (links->flag.type == CRULE_AUTO) 2252 { 2253 for (m = links->mask; m; m = m->next) 2254 sendnumeric(client, RPL_STATSDLINE, 'd', m->mask, links->prettyrule); 2255 } 2256 } 2257 2258 return 1; 2259 }