]> jfr.im git - solanum.git/blame - modules/core/m_server.c
doc: fix whitespace in example configs [ci skip]
[solanum.git] / modules / core / m_server.c
CommitLineData
212380e3
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_server.c: Introduces a server.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
212380e3
AC
23 */
24
25#include "stdinc.h"
212380e3 26#include "client.h" /* client struct */
212380e3 27#include "hash.h" /* add_to_client_hash */
4562c604 28#include "match.h"
212380e3
AC
29#include "ircd.h" /* me */
30#include "numeric.h" /* ERR_xxx */
31#include "s_conf.h" /* struct ConfItem */
32#include "s_newconf.h"
4016731b 33#include "logger.h" /* log level defines */
212380e3
AC
34#include "s_serv.h" /* server_estab, check_server */
35#include "s_stats.h" /* ServerStats */
994544c2 36#include "scache.h"
212380e3
AC
37#include "send.h" /* sendto_one */
38#include "msg.h"
39#include "parse.h"
40#include "modules.h"
41
4491f536 42static const char server_desc[] =
51588bbc 43 "Provides the TS6 commands to introduce a new server to the network";
212380e3 44
3c7d6fcc
EM
45static void mr_server(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
46static void ms_server(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47static void ms_sid(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
48
49static bool bogus_host(const char *host);
50static void set_server_gecos(struct Client *, const char *);
51
212380e3 52struct Message server_msgtab = {
7baa37a9 53 "SERVER", 0, 0, 0, 0,
212380e3
AC
54 {{mr_server, 4}, mg_reg, mg_ignore, {ms_server, 4}, mg_ignore, mg_reg}
55};
56struct Message sid_msgtab = {
7baa37a9 57 "SID", 0, 0, 0, 0,
212380e3
AC
58 {mg_ignore, mg_reg, mg_ignore, {ms_sid, 5}, mg_ignore, mg_reg}
59};
60
61mapi_clist_av1 server_clist[] = { &server_msgtab, &sid_msgtab, NULL };
62
ee6dcb05 63DECLARE_MODULE_AV2(server, NULL, NULL, server_clist, NULL, NULL, NULL, NULL, server_desc);
212380e3 64
212380e3
AC
65/*
66 * mr_server - SERVER message handler
212380e3
AC
67 * parv[1] = servername
68 * parv[2] = serverinfo/hopcount
69 * parv[3] = serverinfo
70 */
3c7d6fcc 71static void
428ca87b 72mr_server(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
73{
74 char info[REALLEN + 1];
75 const char *name;
76 struct Client *target_p;
77 int hop;
79d488b2 78 unsigned int required_mask;
fce4df54 79 const char *missing;
212380e3
AC
80
81 name = parv[1];
82 hop = atoi(parv[2]);
f427c8b0 83 rb_strlcpy(info, parv[3], sizeof(info));
212380e3 84
9c2f9ec9
JT
85 if (IsHandshake(client_p) && irccmp(client_p->name, name))
86 {
87 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
88 "Server %s has unexpected name %s",
b3ebc7ab 89 client_p->name, name);
9c2f9ec9
JT
90 ilog(L_SERVER, "Server %s has unexpected name %s",
91 log_client_name(client_p, SHOW_IP), name);
92 exit_client(client_p, client_p, client_p, "Server name mismatch");
3c7d6fcc 93 return;
9c2f9ec9
JT
94 }
95
55abcbb2 96 /*
212380e3
AC
97 * Reject a direct nonTS server connection if we're TS_ONLY -orabidoo
98 */
99 if(!DoesTS(client_p))
100 {
101 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Link %s dropped, non-TS server",
b3ebc7ab 102 client_p->name);
212380e3 103 exit_client(client_p, client_p, client_p, "Non-TS server");
3c7d6fcc 104 return;
212380e3
AC
105 }
106
107 if(bogus_host(name))
108 {
109 exit_client(client_p, client_p, client_p, "Bogus server name");
3c7d6fcc 110 return;
212380e3
AC
111 }
112
113 /* Now we just have to call check_server and everything should be
114 * check for us... -A1kmm. */
115 switch (check_server(name, client_p))
116 {
117 case -1:
118 if(ConfigFileEntry.warn_no_nline)
119 {
120 sendto_realops_snomask(SNO_GENERAL, L_ALL,
121 "Unauthorised server connection attempt from %s: "
122 "No entry for servername %s",
b1ace057 123 "[@255.255.255.255]", name);
212380e3
AC
124
125 ilog(L_SERVER, "Access denied, no connect block for server %s%s",
126 EmptyString(client_p->name) ? name : "",
127 log_client_name(client_p, SHOW_IP));
128 }
129
130 exit_client(client_p, client_p, client_p, "Invalid servername.");
3c7d6fcc 131 return;
212380e3
AC
132 /* NOT REACHED */
133 break;
134
135 case -2:
a58cdfa3 136 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
212380e3 137 "Unauthorised server connection attempt from %s: "
ff0cc1e6 138 "Bad credentials for server %s",
b1ace057 139 "[@255.255.255.255]", name);
212380e3 140
ff0cc1e6 141 ilog(L_SERVER, "Access denied, invalid credentials for server %s%s",
212380e3
AC
142 EmptyString(client_p->name) ? name : "",
143 log_client_name(client_p, SHOW_IP));
144
ff0cc1e6 145 exit_client(client_p, client_p, client_p, "Invalid credentials.");
3c7d6fcc 146 return;
212380e3
AC
147 /* NOT REACHED */
148 break;
149
150 case -3:
151 sendto_realops_snomask(SNO_GENERAL, L_ALL,
152 "Unauthorised server connection attempt from %s: "
153 "Invalid host for server %s",
b1ace057 154 "[@255.255.255.255]", name);
212380e3
AC
155
156 ilog(L_SERVER, "Access denied, invalid host for server %s%s",
157 EmptyString(client_p->name) ? name : "",
158 log_client_name(client_p, SHOW_IP));
159
160 exit_client(client_p, client_p, client_p, "Invalid host.");
3c7d6fcc 161 return;
212380e3
AC
162 /* NOT REACHED */
163 break;
164
165 /* servername is > HOSTLEN */
166 case -4:
167 sendto_realops_snomask(SNO_GENERAL, L_ALL,
168 "Invalid servername %s from %s",
b1ace057 169 name, "[@255.255.255.255]");
212380e3
AC
170 ilog(L_SERVER, "Access denied, invalid servername from %s",
171 log_client_name(client_p, SHOW_IP));
172
173 exit_client(client_p, client_p, client_p, "Invalid servername.");
3c7d6fcc 174 return;
212380e3
AC
175 /* NOT REACHED */
176 break;
c6d72037 177 case -5:
8bd5767b
JT
178 sendto_realops_snomask(SNO_GENERAL, L_ALL,
179 "Connection from servername %s requires SSL/TLS but is plaintext",
180 name);
55abcbb2 181 ilog(L_SERVER, "Access denied, requires SSL/TLS but is plaintext from %s",
8bd5767b
JT
182 log_client_name(client_p, SHOW_IP));
183
184 exit_client(client_p, client_p, client_p, "Access denied, requires SSL/TLS but is plaintext");
3c7d6fcc 185 return;
212380e3
AC
186 }
187
316cbf11
JT
188 /* require TS6 for direct links */
189 if(!IsCapable(client_p, CAP_TS6))
190 {
191 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
192 "Link %s dropped, TS6 protocol is required", name);
193 exit_client(client_p, client_p, client_p, "Incompatible TS version");
3c7d6fcc 194 return;
316cbf11
JT
195 }
196
22b24f63 197 /* check to ensure any "required" caps are set. --nenolod */
22b24f63
JT
198 required_mask = capability_index_get_required(serv_capindex);
199 if (!IsCapable(client_p, required_mask))
200 {
fce4df54
JT
201 missing = capability_index_list(serv_capindex, required_mask &
202 ~client_p->localClient->caps);
22b24f63 203 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
fce4df54
JT
204 "Link %s dropped, required CAPABs [%s] are missing",
205 name, missing);
206 ilog(L_SERVER, "Link %s%s dropped, required CAPABs [%s] are missing",
22b24f63 207 EmptyString(client_p->name) ? name : "",
fce4df54
JT
208 log_client_name(client_p, SHOW_IP), missing);
209 /* Do not use '[' in the below message because it would cause
210 * it to be considered potentially unsafe (might disclose IP
211 * addresses)
212 */
213 sendto_one(client_p, "ERROR :Missing required CAPABs (%s)", missing);
22b24f63
JT
214 exit_client(client_p, client_p, client_p, "Missing required CAPABs");
215
3c7d6fcc 216 return;
22b24f63
JT
217 }
218
b0b7de54 219 if((target_p = find_server(NULL, name)))
212380e3
AC
220 {
221 /*
222 * This link is trying feed me a server that I already have
223 * access through another path -- multiple paths not accepted
224 * currently, kill this link immediately!!
225 *
226 * Rather than KILL the link which introduced it, KILL the
227 * youngest of the two links. -avalon
228 *
229 * Definitely don't do that here. This is from an unregistered
230 * connect - A1kmm.
231 */
7b054ca3
JT
232 if (target_p->servptr->flags & FLAGS_SERVICE)
233 {
234 /* Assume any servers introduced by services
235 * are jupes.
236 * -- jilles
237 */
238 sendto_one(client_p, "ERROR :Server juped.");
239 }
240 else
241 {
242 sendto_realops_snomask(SNO_GENERAL, L_ALL,
243 "Attempt to re-introduce server %s from %s",
244 name, "[@255.255.255.255]");
245 ilog(L_SERVER, "Attempt to re-introduce server %s from %s",
246 name, log_client_name(client_p, SHOW_IP));
212380e3 247
7b054ca3
JT
248 sendto_one(client_p, "ERROR :Server already exists.");
249 }
212380e3 250 exit_client(client_p, client_p, client_p, "Server Exists");
3c7d6fcc 251 return;
212380e3
AC
252 }
253
254 if(has_id(client_p) && (target_p = find_id(client_p->id)) != NULL)
255 {
a58cdfa3 256 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
8e34ffc6 257 "Attempt to re-introduce SID %s from %s%s (already in use by %s)",
212380e3
AC
258 client_p->id,
259 EmptyString(client_p->name) ? name : "",
8e34ffc6
JT
260 client_p->name, target_p->name);
261 ilog(L_SERVER, "Attempt to re-introduce SID %s from %s%s (already in use by %s)",
212380e3
AC
262 client_p->id,
263 EmptyString(client_p->name) ? name : "",
8e34ffc6
JT
264 log_client_name(client_p, SHOW_IP),
265 target_p->name);
212380e3
AC
266
267 sendto_one(client_p, "ERROR :SID already exists.");
268 exit_client(client_p, client_p, client_p, "SID Exists");
3c7d6fcc 269 return;
212380e3
AC
270 }
271
272 /*
273 * if we are connecting (Handshake), we already have the name from the
274 * C:line in client_p->name
275 */
276
f427c8b0 277 rb_strlcpy(client_p->name, name, sizeof(client_p->name));
212380e3
AC
278 set_server_gecos(client_p, info);
279 client_p->hopcount = hop;
280 server_estab(client_p);
212380e3
AC
281}
282
283/*
284 * ms_server - SERVER message handler
212380e3
AC
285 * parv[1] = servername
286 * parv[2] = serverinfo/hopcount
287 * parv[3] = serverinfo
288 */
3c7d6fcc 289static void
428ca87b 290ms_server(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
291{
292 char info[REALLEN + 1];
293 /* same size as in s_misc.c */
294 const char *name;
295 struct Client *target_p;
296 struct remote_conf *hub_p;
297 hook_data_client hdata;
298 int hop;
299 int hlined = 0;
300 int llined = 0;
5b96d9a6 301 rb_dlink_node *ptr;
7d428759 302 char squitreason[160];
212380e3
AC
303
304 name = parv[1];
305 hop = atoi(parv[2]);
f427c8b0 306 rb_strlcpy(info, parv[3], sizeof(info));
212380e3 307
dc336d1a 308 if(find_server(NULL, name))
212380e3
AC
309 {
310 /*
311 * This link is trying feed me a server that I already have
312 * access through another path -- multiple paths not accepted
313 * currently, kill this link immediately!!
314 *
315 * Rather than KILL the link which introduced it, KILL the
316 * youngest of the two links. -avalon
317 *
318 * I think that we should exit the link itself, not the introducer,
319 * and we should always exit the most recently received(i.e. the
320 * one we are receiving this SERVER for. -A1kmm
321 *
322 * You *cant* do this, if you link somewhere, it bursts you a server
323 * that already exists, then sends you a client burst, you squit the
324 * server, but you keep getting the burst of clients on a server that
325 * doesnt exist, although ircd can handle it, its not a realistic
55abcbb2 326 * solution.. --fl_
212380e3 327 */
212380e3
AC
328 ilog(L_SERVER, "Link %s cancelled, server %s already exists",
329 client_p->name, name);
330
5203cba5 331 snprintf(squitreason, sizeof squitreason,
7d428759
JT
332 "Server %s already exists",
333 name);
334 exit_client(client_p, client_p, &me, squitreason);
3c7d6fcc 335 return;
212380e3
AC
336 }
337
55abcbb2 338 /*
212380e3
AC
339 * User nicks never have '.' in them and server names
340 * must always have '.' in them.
341 */
342 if(strchr(name, '.') == NULL)
343 {
344 /*
345 * Server trying to use the same name as a person. Would
346 * cause a fair bit of confusion. Enough to make it hellish
347 * for a while and servers to send stuff to the wrong place.
348 */
349 sendto_one(client_p, "ERROR :Nickname %s already exists!", name);
350 sendto_realops_snomask(SNO_GENERAL, L_ALL,
351 "Link %s cancelled: Server/nick collision on %s",
b3ebc7ab 352 client_p->name, name);
212380e3
AC
353 ilog(L_SERVER, "Link %s cancelled: Server/nick collision on %s",
354 client_p->name, name);
355
356 exit_client(client_p, client_p, client_p, "Nick as Server");
3c7d6fcc 357 return;
212380e3
AC
358 }
359
360 /*
361 * Server is informing about a new server behind
362 * this link. Create REMOTE server structure,
363 * add it to list and propagate word to my other
364 * server links...
365 */
212380e3
AC
366
367 /*
368 * See if the newly found server is behind a guaranteed
369 * leaf. If so, close the link.
370 *
371 */
5b96d9a6 372 RB_DLINK_FOREACH(ptr, hubleaf_conf_list.head)
212380e3
AC
373 {
374 hub_p = ptr->data;
375
376 if(match(hub_p->server, client_p->name) && match(hub_p->host, name))
377 {
378 if(hub_p->flags & CONF_HUB)
379 hlined++;
380 else
381 llined++;
382 }
383 }
384
385 /* Ok, this way this works is
386 *
387 * A server can have a CONF_HUB allowing it to introduce servers
388 * behind it.
389 *
390 * connect {
391 * name = "irc.bighub.net";
392 * hub_mask="*";
393 * ...
55abcbb2 394 *
212380e3
AC
395 * That would allow "irc.bighub.net" to introduce anything it wanted..
396 *
397 * However
398 *
399 * connect {
400 * name = "irc.somehub.fi";
401 * hub_mask="*";
402 * leaf_mask="*.edu";
403 *...
404 * Would allow this server in finland to hub anything but
405 * .edu's
406 */
407
847ce0e9 408 /* Ok, check client_p can hub the new server */
212380e3
AC
409 if(!hlined)
410 {
411 /* OOOPs nope can't HUB */
412 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Non-Hub link %s introduced %s.",
b3ebc7ab 413 client_p->name, name);
212380e3
AC
414 ilog(L_SERVER, "Non-Hub link %s introduced %s.",
415 client_p->name, name);
416
5203cba5 417 snprintf(squitreason, sizeof squitreason,
8f7ca682
JT
418 "No matching hub_mask for %s",
419 name);
420 exit_client(NULL, client_p, &me, squitreason);
3c7d6fcc 421 return;
212380e3
AC
422 }
423
424 /* Check for the new server being leafed behind this HUB */
425 if(llined)
426 {
427 /* OOOPs nope can't HUB this leaf */
428 sendto_realops_snomask(SNO_GENERAL, L_ALL,
429 "Link %s introduced leafed server %s.",
b3ebc7ab 430 client_p->name, name);
212380e3 431 ilog(L_SERVER, "Link %s introduced leafed server %s.",
55abcbb2 432 client_p->name, name);
212380e3 433
5203cba5 434 snprintf(squitreason, sizeof squitreason,
8f7ca682
JT
435 "Matching leaf_mask for %s",
436 name);
437 exit_client(NULL, client_p, &me, squitreason);
3c7d6fcc 438 return;
212380e3
AC
439 }
440
441
442
443 if(strlen(name) > HOSTLEN)
444 {
445 sendto_realops_snomask(SNO_GENERAL, L_ALL,
446 "Link %s introduced server with invalid servername %s",
b3ebc7ab 447 client_p->name, name);
212380e3
AC
448 ilog(L_SERVER, "Link %s introduced server with invalid servername %s",
449 client_p->name, name);
450
451 exit_client(NULL, client_p, &me, "Invalid servername introduced.");
3c7d6fcc 452 return;
212380e3
AC
453 }
454
455 target_p = make_client(client_p);
456 make_server(target_p);
457 target_p->hopcount = hop;
458
f427c8b0 459 rb_strlcpy(target_p->name, name, sizeof(target_p->name));
212380e3
AC
460
461 set_server_gecos(target_p, info);
462
212380e3
AC
463 target_p->servptr = source_p;
464
465 SetServer(target_p);
466
0e7cb7e6
JT
467 rb_dlinkAddTail(target_p, &target_p->node, &global_client_list);
468 rb_dlinkAddTailAlloc(target_p, &global_serv_list);
212380e3 469 add_to_client_hash(target_p->name, target_p);
0e7cb7e6 470 rb_dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->servers);
212380e3 471
994544c2
JT
472 target_p->serv->nameinfo = scache_connect(target_p->name, target_p->info, IsHidden(target_p));
473
212380e3
AC
474 sendto_server(client_p, NULL, NOCAPS, NOCAPS,
475 ":%s SERVER %s %d :%s%s",
476 source_p->name, target_p->name, target_p->hopcount + 1,
477 IsHidden(target_p) ? "(H) " : "", target_p->info);
478
479 sendto_realops_snomask(SNO_EXTERNAL, L_ALL,
480 "Server %s being introduced by %s", target_p->name, source_p->name);
481
482 /* quick, dirty EOB. you know you love it. */
483 sendto_one(target_p, ":%s PING %s %s", get_id(&me, target_p), me.name, target_p->name);
484
485 hdata.client = source_p;
486 hdata.target = target_p;
487 call_hook(h_server_introduced, &hdata);
212380e3
AC
488}
489
3c7d6fcc 490static void
428ca87b 491ms_sid(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
492{
493 struct Client *target_p;
494 struct remote_conf *hub_p;
495 hook_data_client hdata;
5b96d9a6 496 rb_dlink_node *ptr;
212380e3
AC
497 int hlined = 0;
498 int llined = 0;
8e34ffc6 499 char squitreason[160];
212380e3 500
212380e3 501 /* collision on the name? */
dc336d1a 502 if(find_server(NULL, parv[1]) != NULL)
212380e3 503 {
212380e3
AC
504 ilog(L_SERVER, "Link %s cancelled, server %s already exists",
505 client_p->name, parv[1]);
506
5203cba5 507 snprintf(squitreason, sizeof squitreason,
7d428759
JT
508 "Server %s already exists",
509 parv[1]);
510 exit_client(NULL, client_p, &me, squitreason);
3c7d6fcc 511 return;
212380e3
AC
512 }
513
514 /* collision on the SID? */
515 if((target_p = find_id(parv[3])) != NULL)
516 {
8e34ffc6
JT
517 sendto_wallops_flags(UMODE_WALLOP, &me,
518 "Link %s cancelled, SID %s for server %s already in use by %s",
519 client_p->name, parv[3], parv[1], target_p->name);
520 sendto_server(NULL, NULL, CAP_TS6, NOCAPS,
521 ":%s WALLOPS :Link %s cancelled, SID %s for server %s already in use by %s",
522 me.id, client_p->name, parv[3], parv[1], target_p->name);
523 ilog(L_SERVER, "Link %s cancelled, SID %s for server %s already in use by %s",
524 client_p->name, parv[3], parv[1], target_p->name);
525
5203cba5 526 snprintf(squitreason, sizeof squitreason,
8e34ffc6
JT
527 "SID %s for %s already in use by %s",
528 parv[3], parv[1], target_p->name);
529 exit_client(NULL, client_p, &me, squitreason);
3c7d6fcc 530 return;
212380e3
AC
531 }
532
533 if(bogus_host(parv[1]) || strlen(parv[1]) > HOSTLEN)
534 {
535 sendto_one(client_p, "ERROR :Invalid servername");
536 sendto_realops_snomask(SNO_GENERAL, L_ALL,
537 "Link %s cancelled, servername %s invalid",
b3ebc7ab 538 client_p->name, parv[1]);
212380e3
AC
539 ilog(L_SERVER, "Link %s cancelled, servername %s invalid",
540 client_p->name, parv[1]);
541
542 exit_client(NULL, client_p, &me, "Bogus server name");
3c7d6fcc 543 return;
212380e3
AC
544 }
545
546 if(!IsDigit(parv[3][0]) || !IsIdChar(parv[3][1]) ||
547 !IsIdChar(parv[3][2]) || parv[3][3] != '\0')
548 {
549 sendto_one(client_p, "ERROR :Invalid SID");
550 sendto_realops_snomask(SNO_GENERAL, L_ALL,
551 "Link %s cancelled, SID %s invalid",
b3ebc7ab 552 client_p->name, parv[3]);
212380e3
AC
553 ilog(L_SERVER, "Link %s cancelled, SID %s invalid",
554 client_p->name, parv[3]);
555
556 exit_client(NULL, client_p, &me, "Bogus SID");
3c7d6fcc 557 return;
212380e3
AC
558 }
559
560 /* for the directly connected server:
561 * H: allows it to introduce a server matching that mask
562 * L: disallows it introducing a server matching that mask
563 */
5b96d9a6 564 RB_DLINK_FOREACH(ptr, hubleaf_conf_list.head)
212380e3
AC
565 {
566 hub_p = ptr->data;
567
568 if(match(hub_p->server, client_p->name) && match(hub_p->host, parv[1]))
569 {
570 if(hub_p->flags & CONF_HUB)
571 hlined++;
572 else
573 llined++;
574 }
575 }
576
577 /* no matching hub_mask */
578 if(!hlined)
579 {
212380e3
AC
580 sendto_realops_snomask(SNO_GENERAL, L_ALL,
581 "Non-Hub link %s introduced %s.",
b3ebc7ab 582 client_p->name, parv[1]);
212380e3
AC
583 ilog(L_SERVER, "Non-Hub link %s introduced %s.",
584 client_p->name, parv[1]);
8f7ca682 585
5203cba5 586 snprintf(squitreason, sizeof squitreason,
8f7ca682
JT
587 "No matching hub_mask for %s",
588 parv[1]);
589 exit_client(NULL, client_p, &me, squitreason);
3c7d6fcc 590 return;
212380e3
AC
591 }
592
593 /* matching leaf_mask */
594 if(llined)
595 {
212380e3
AC
596 sendto_realops_snomask(SNO_GENERAL, L_ALL,
597 "Link %s introduced leafed server %s.",
b3ebc7ab 598 client_p->name, parv[1]);
212380e3 599 ilog(L_SERVER, "Link %s introduced leafed server %s.",
55abcbb2 600 client_p->name, parv[1]);
8f7ca682 601
5203cba5 602 snprintf(squitreason, sizeof squitreason,
8f7ca682
JT
603 "Matching leaf_mask for %s",
604 parv[1]);
605 exit_client(NULL, client_p, &me, squitreason);
3c7d6fcc 606 return;
212380e3
AC
607 }
608
609 /* ok, alls good */
610 target_p = make_client(client_p);
611 make_server(target_p);
612
f427c8b0 613 rb_strlcpy(target_p->name, parv[1], sizeof(target_p->name));
212380e3
AC
614 target_p->hopcount = atoi(parv[2]);
615 strcpy(target_p->id, parv[3]);
616 set_server_gecos(target_p, parv[4]);
617
212380e3
AC
618 target_p->servptr = source_p;
619 SetServer(target_p);
620
0e7cb7e6
JT
621 rb_dlinkAddTail(target_p, &target_p->node, &global_client_list);
622 rb_dlinkAddTailAlloc(target_p, &global_serv_list);
212380e3
AC
623 add_to_client_hash(target_p->name, target_p);
624 add_to_id_hash(target_p->id, target_p);
0e7cb7e6 625 rb_dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->servers);
212380e3 626
994544c2
JT
627 target_p->serv->nameinfo = scache_connect(target_p->name, target_p->info, IsHidden(target_p));
628
212380e3
AC
629 sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
630 ":%s SID %s %d %s :%s%s",
631 source_p->id, target_p->name, target_p->hopcount + 1,
632 target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
212380e3
AC
633
634 sendto_realops_snomask(SNO_EXTERNAL, L_ALL,
635 "Server %s being introduced by %s", target_p->name, source_p->name);
636
637 /* quick, dirty EOB. you know you love it. */
638 sendto_one(target_p, ":%s PING %s %s",
639 get_id(&me, target_p), me.name, get_id(target_p, target_p));
640
641 hdata.client = source_p;
642 hdata.target = target_p;
643 call_hook(h_server_introduced, &hdata);
212380e3
AC
644}
645
646/* set_server_gecos()
647 *
648 * input - pointer to client
649 * output - none
650 * side effects - servers gecos field is set
651 */
3c7d6fcc 652static void
212380e3
AC
653set_server_gecos(struct Client *client_p, const char *info)
654{
655 /* check the info for [IP] */
656 if(info[0])
657 {
658 char *p;
659 char *s;
212380e3
AC
660
661 s = LOCAL_COPY(info);
662
663 /* we should only check the first word for an ip */
664 if((p = strchr(s, ' ')))
665 *p = '\0';
666
667 /* check for a ] which would symbolise an [IP] */
f93bc397 668 if(strchr(s, ']'))
212380e3
AC
669 {
670 /* set s to after the first space */
671 if(p)
672 s = ++p;
673 else
674 s = NULL;
675 }
676 /* no ], put the space back */
677 else if(p)
678 *p = ' ';
679
680 /* p may have been set to a trailing space, so check s exists and that
681 * it isnt \0 */
682 if(s && (*s != '\0'))
683 {
684 /* a space? if not (H) could be the last part of info.. */
685 if((p = strchr(s, ' ')))
686 *p = '\0';
687
688 /* check for (H) which is a hidden server */
689 if(!strcmp(s, "(H)"))
690 {
691 SetHidden(client_p);
692
693 /* if there was no space.. theres nothing to set info to */
694 if(p)
695 s = ++p;
696 else
697 s = NULL;
698 }
699 else if(p)
700 *p = ' ';
701
702 /* if there was a trailing space, s could point to \0, so check */
703 if(s && (*s != '\0'))
704 {
f427c8b0 705 rb_strlcpy(client_p->info, s, sizeof(client_p->info));
3c7d6fcc 706 return;
212380e3
AC
707 }
708 }
709 }
710
f427c8b0 711 rb_strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info));
212380e3
AC
712}
713
714/*
715 * bogus_host
716 *
717 * inputs - hostname
3c7d6fcc 718 * output - true if a bogus hostname input, false if its valid
212380e3
AC
719 * side effects - none
720 */
3c7d6fcc 721static bool
212380e3
AC
722bogus_host(const char *host)
723{
3c7d6fcc 724 bool bogus_server = false;
212380e3
AC
725 const char *s;
726 int dots = 0;
727
728 for(s = host; *s; s++)
729 {
730 if(!IsServChar(*s))
731 {
3c7d6fcc 732 bogus_server = true;
212380e3
AC
733 break;
734 }
735 if('.' == *s)
736 ++dots;
737 }
738
739 if(!dots || bogus_server)
3c7d6fcc 740 return true;
212380e3 741
3c7d6fcc 742 return false;
212380e3 743}