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 }