ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_server.c
Revision: 7963
Committed: Mon Mar 13 18:50:04 2017 UTC (9 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 27521 byte(s)
Error occurred while calculating annotation data.
Log Message:
- No longer put servers on the 'global_client_list'. This was just bad.

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2017 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file m_server.c
23 * \brief Includes required functions for processing the SERVER/SID command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "event.h"
31 #include "hash.h"
32 #include "id.h"
33 #include "irc_string.h"
34 #include "ircd.h"
35 #include "numeric.h"
36 #include "conf.h"
37 #include "conf_service.h"
38 #include "log.h"
39 #include "misc.h"
40 #include "server.h"
41 #include "user.h"
42 #include "send.h"
43 #include "parse.h"
44 #include "memory.h"
45 #include "modules.h"
46
47
48 /*! Parses server flags to be potentially set
49 * \param client_p Pointer to server's Client structure
50 * \param flags Pointer to the flag string to be parsed
51 */
52 static void
53 server_set_flags(struct Client *client_p, const char *flags)
54 {
55 const unsigned char *p = (const unsigned char *)flags;
56
57 if (*p != '+')
58 return;
59
60 while (*++p)
61 {
62 switch (*p)
63 {
64 case 'h':
65 AddFlag(client_p, FLAGS_HIDDEN);
66 break;
67 default:
68 break;
69 }
70 }
71 }
72
73 /*
74 * send_tb
75 *
76 * inputs - pointer to Client
77 * - pointer to channel
78 * output - NONE
79 * side effects - Called on a server burst when
80 * server is CAPAB_TBURST capable
81 */
82 static void
83 server_send_tburst(struct Client *client_p, const struct Channel *chptr)
84 {
85 /*
86 * We may also send an empty topic here, but only if topic_time isn't 0,
87 * i.e. if we had a topic that got unset. This is required for syncing
88 * topics properly.
89 *
90 * Imagine the following scenario: Our downlink introduces a channel
91 * to us with a TS that is equal to ours, but the channel topic on
92 * their side got unset while the servers were in splitmode, which means
93 * their 'topic' is newer. They simply wanted to unset it, so we have to
94 * deal with it in a more sophisticated fashion instead of just resetting
95 * it to their old topic they had before. Read m_tburst.c:ms_tburst
96 * for further information -Michael
97 */
98 if (chptr->topic_time)
99 sendto_one(client_p, ":%s TBURST %ju %s %ju %s :%s", me.id,
100 chptr->creationtime, chptr->name,
101 chptr->topic_time,
102 chptr->topic_info,
103 chptr->topic);
104 }
105
106 /* sendnick_TS()
107 *
108 * inputs - client (server) to send nick towards
109 * - client to send nick for
110 * output - NONE
111 * side effects - NICK message is sent towards given client_p
112 */
113 static void
114 server_send_client(struct Client *client_p, struct Client *target_p)
115 {
116 dlink_node *node = NULL;
117 char ubuf[IRCD_BUFSIZE] = "";
118
119 assert(IsClient(target_p));
120
121 send_umode(target_p, 0, 0, ubuf);
122
123 if (ubuf[0] == '\0')
124 {
125 ubuf[0] = '+';
126 ubuf[1] = '\0';
127 }
128
129 sendto_one(client_p, ":%s UID %s %u %ju %s %s %s %s %s %s :%s",
130 target_p->servptr->id,
131 target_p->name, target_p->hopcount + 1,
132 target_p->tsinfo,
133 ubuf, target_p->username, target_p->host,
134 target_p->sockhost, target_p->id,
135 target_p->account, target_p->info);
136
137 if (!EmptyString(target_p->certfp))
138 sendto_one(client_p, ":%s CERTFP %s", target_p->id, target_p->certfp);
139
140 if (target_p->away[0])
141 sendto_one(client_p, ":%s AWAY :%s", target_p->id, target_p->away);
142
143
144 DLINK_FOREACH(node, target_p->svstags.head)
145 {
146 const struct ServicesTag *svstag = node->data;
147 char *m = ubuf;
148
149 for (const struct user_modes *tab = umode_tab; tab->c; ++tab)
150 if (svstag->umodes & tab->flag)
151 *m++ = tab->c;
152 *m = '\0';
153
154 sendto_one(client_p, ":%s SVSTAG %s %ju %u +%s :%s", me.id, target_p->id,
155 target_p->tsinfo, svstag->numeric, ubuf, svstag->tag);
156 }
157 }
158
159 /* burst_all()
160 *
161 * inputs - pointer to server to send burst to
162 * output - NONE
163 * side effects - complete burst of channels/nicks is sent to client_p
164 */
165 static void
166 server_burst(struct Client *client_p)
167 {
168 dlink_node *node = NULL;
169
170 DLINK_FOREACH(node, global_client_list.head)
171 {
172 struct Client *target_p = node->data;
173
174 if (target_p->from != client_p)
175 server_send_client(client_p, target_p);
176 }
177
178 DLINK_FOREACH(node, channel_list.head)
179 {
180 struct Channel *chptr = node->data;
181
182 if (dlink_list_length(&chptr->members))
183 {
184 channel_send_modes(client_p, chptr);
185
186 if (IsCapable(client_p, CAPAB_TBURST))
187 server_send_tburst(client_p, chptr);
188 }
189 }
190
191 /* Always send a PING after connect burst is done */
192 sendto_one(client_p, "PING :%s", me.id);
193 }
194
195 /* server_estab()
196 *
197 * inputs - pointer to a struct Client
198 * output -
199 * side effects -
200 */
201 static void
202 server_estab(struct Client *client_p)
203 {
204 struct MaskItem *conf = NULL;
205 dlink_node *node = NULL;
206
207 if ((conf = find_conf_name(&client_p->connection->confs, client_p->name, CONF_SERVER)) == NULL)
208 {
209 /* This shouldn't happen, better tell the ops... -A1kmm */
210 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
211 "Warning: lost connect{} block for %s",
212 get_client_name(client_p, SHOW_IP));
213 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
214 "Warning: lost connect{} block for %s",
215 get_client_name(client_p, MASK_IP));
216 exit_client(client_p, "Lost connect{} block!");
217 return;
218 }
219
220 xfree(client_p->connection->password);
221 client_p->connection->password = NULL;
222
223 if (!ConfigServerInfo.hub && dlink_list_length(&local_server_list))
224 {
225 ++ServerStats.is_ref;
226 exit_client(client_p, "I'm a leaf not a hub");
227 return;
228 }
229
230 if (IsUnknown(client_p))
231 {
232 sendto_one(client_p, "PASS %s TS %u %s", conf->spasswd, TS_CURRENT, me.id);
233
234 sendto_one(client_p, "CAPAB :%s", get_capabilities(NULL));
235
236 sendto_one(client_p, "SERVER %s 1 :%s%s",
237 me.name, ConfigServerHide.hidden ? "(H) " : "", me.info);
238 }
239
240 sendto_one(client_p, ":%s SVINFO %u %u 0 :%ju", me.id, TS_CURRENT, TS_MIN,
241 CurrentTime);
242
243 /* *WARNING*
244 ** In the following code in place of plain server's
245 ** name we send what is returned by get_client_name
246 ** which may add the "sockhost" after the name. It's
247 ** *very* *important* that there is a SPACE between
248 ** the name and sockhost (if present). The receiving
249 ** server will start the information field from this
250 ** first blank and thus puts the sockhost into info.
251 ** ...a bit tricky, but you have been warned, besides
252 ** code is more neat this way... --msa
253 */
254 client_p->servptr = &me;
255
256 if (HasFlag(client_p, FLAGS_CLOSING))
257 return;
258
259 SetServer(client_p);
260
261 /* Some day, all these lists will be consolidated *sigh* */
262 dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
263
264 assert(dlinkFind(&unknown_list, client_p));
265
266 dlink_move_node(&client_p->connection->lclient_node,
267 &unknown_list, &local_server_list);
268
269 Count.myserver++;
270
271 dlinkAdd(client_p, &client_p->node, &global_server_list);
272 hash_add_client(client_p);
273 hash_add_id(client_p);
274
275 /* Doesn't duplicate client_p->serv if allocated this struct already */
276 make_server(client_p);
277
278 /* Fixing eob timings.. -gnp */
279 client_p->connection->firsttime = CurrentTime;
280
281 if (service_find(client_p->name))
282 AddFlag(client_p, FLAGS_SERVICE);
283
284 /* Show the real host/IP to admins */
285 if (tls_isusing(&client_p->connection->fd.ssl))
286 {
287 /* Show the real host/IP to admins */
288 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
289 "Link with %s established: [TLS: %s] (Capabilities: %s)",
290 get_client_name(client_p, SHOW_IP), tls_get_cipher(&client_p->connection->fd.ssl),
291 get_capabilities(client_p));
292
293 /* Now show the masked hostname/IP to opers */
294 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
295 "Link with %s established: [TLS: %s] (Capabilities: %s)",
296 get_client_name(client_p, MASK_IP), tls_get_cipher(&client_p->connection->fd.ssl),
297 get_capabilities(client_p));
298 ilog(LOG_TYPE_IRCD, "Link with %s established: [TLS: %s] (Capabilities: %s)",
299 get_client_name(client_p, SHOW_IP), tls_get_cipher(&client_p->connection->fd.ssl),
300 get_capabilities(client_p));
301 }
302 else
303 {
304 /* Show the real host/IP to admins */
305 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
306 "Link with %s established: (Capabilities: %s)",
307 get_client_name(client_p, SHOW_IP), get_capabilities(client_p));
308 /* Now show the masked hostname/IP to opers */
309 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
310 "Link with %s established: (Capabilities: %s)",
311 get_client_name(client_p, MASK_IP), get_capabilities(client_p));
312 ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)",
313 get_client_name(client_p, SHOW_IP), get_capabilities(client_p));
314 }
315
316 fd_note(&client_p->connection->fd, "Server: %s", client_p->name);
317
318 sendto_server(client_p, 0, 0, ":%s SID %s 2 %s :%s%s",
319 me.id, client_p->name, client_p->id,
320 IsHidden(client_p) ? "(H) " : "", client_p->info);
321
322 /*
323 * Pass on my client information to the new server
324 *
325 * First, pass only servers (idea is that if the link gets
326 * cancelled beacause the server was already there,
327 * there are no NICK's to be cancelled...). Of course,
328 * if cancellation occurs, all this info is sent anyway,
329 * and I guess the link dies when a read is attempted...? --msa
330 *
331 * Note: Link cancellation to occur at this point means
332 * that at least two servers from my fragment are building
333 * up connection this other fragment at the same time, it's
334 * a race condition, not the normal way of operation...
335 */
336 DLINK_FOREACH_PREV(node, global_server_list.tail)
337 {
338 struct Client *target_p = node->data;
339
340 /* target_p->from == target_p for target_p == client_p */
341 if (IsMe(target_p) || target_p->from == client_p)
342 continue;
343
344 sendto_one(client_p, ":%s SID %s %u %s :%s%s",
345 target_p->servptr->id, target_p->name, target_p->hopcount+1,
346 target_p->id, IsHidden(target_p) ? "(H) " : "",
347 target_p->info);
348 }
349
350 server_burst(client_p);
351
352 if (IsCapable(client_p, CAPAB_EOB))
353 {
354 DLINK_FOREACH_PREV(node, global_server_list.tail)
355 {
356 struct Client *target_p = node->data;
357
358 if (target_p->from == client_p)
359 continue;
360
361 if (IsMe(target_p) || HasFlag(target_p, FLAGS_EOB))
362 sendto_one(client_p, ":%s EOB", target_p->id);
363 }
364 }
365 }
366
367 /* set_server_gecos()
368 *
369 * input - pointer to client
370 * output - NONE
371 * side effects - servers gecos field is set
372 */
373 static void
374 server_set_gecos(struct Client *client_p, const char *info)
375 {
376 const char *s = info;
377
378 /* check for (H) which is a hidden server */
379 if (!strncmp(s, "(H) ", 4))
380 {
381 AddFlag(client_p, FLAGS_HIDDEN);
382 s = s + 4;
383 }
384
385 if (!EmptyString(s))
386 strlcpy(client_p->info, s, sizeof(client_p->info));
387 else
388 strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info));
389 }
390
391 static int
392 server_check(const char *name, struct Client *client_p)
393 {
394 dlink_node *node = NULL;
395 struct MaskItem *server_conf = NULL;
396 int error = -1;
397
398 assert(client_p);
399
400 /* Loop through looking for all possible connect items that might work */
401 DLINK_FOREACH(node, connect_items.head)
402 {
403 struct MaskItem *conf = node->data;
404
405 if (irccmp(name, conf->name))
406 continue;
407
408 error = -3;
409
410 if (!irccmp(conf->host, client_p->host) ||
411 !irccmp(conf->host, client_p->sockhost))
412 {
413 error = -2;
414
415 if (!match_conf_password(client_p->connection->password, conf))
416 return -2;
417
418 if (!EmptyString(conf->certfp))
419 if (EmptyString(client_p->certfp) || strcasecmp(client_p->certfp, conf->certfp))
420 return -4;
421
422 server_conf = conf;
423 }
424 }
425
426 if (server_conf == NULL)
427 return error;
428
429 attach_conf(client_p, server_conf);
430
431 switch (server_conf->aftype)
432 {
433 case AF_INET6:
434 {
435 const struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&server_conf->addr;
436
437 if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr))
438 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
439 break;
440 }
441 case AF_INET:
442 {
443 const struct sockaddr_in *v4 = (struct sockaddr_in *)&server_conf->addr;
444
445 if (v4->sin_addr.s_addr == INADDR_NONE)
446 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
447 break;
448 }
449 }
450
451 return 0;
452 }
453
454 /* mr_server()
455 * parv[0] = command
456 * parv[1] = servername
457 * parv[2] = hopcount
458 * parv[3] = serverinfo
459 *
460 * 8.3.x+:
461 * parv[0] = command
462 * parv[1] = servername
463 * parv[2] = hopcount
464 * parv[3] = sid
465 * parv[4] = string of flags starting with '+'
466 * parv[5] = serverinfo
467 */
468 static int
469 mr_server(struct Client *source_p, int parc, char *parv[])
470 {
471 const char *name = parv[1];
472 const char *sid = parc == 6 ? parv[3] : source_p->id; /* TBR: compatibility 'mode' */
473 struct Client *target_p = NULL;
474
475 if (EmptyString(parv[parc - 1]))
476 {
477 exit_client(source_p, "No server description supplied");
478 return 0;
479 }
480
481 if (!valid_servname(name))
482 {
483 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
484 "Unauthorized server connection attempt from %s: Bogus server name "
485 "for server %s", get_client_name(source_p, SHOW_IP), name);
486 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
487 "Unauthorized server connection attempt from %s: Bogus server name "
488 "for server %s", get_client_name(source_p, MASK_IP), name);
489 exit_client(source_p, "Bogus server name");
490 return 0;
491 }
492
493 if (!valid_sid(sid))
494 {
495 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
496 "Link %s introduced server with bogus server ID %s",
497 get_client_name(source_p, SHOW_IP), sid);
498 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
499 "Link %s introduced server with bogus server ID %s",
500 get_client_name(source_p, MASK_IP), sid);
501 exit_client(source_p, "Bogus server ID introduced");
502 return 0;
503 }
504
505 /* Now we just have to call server_check() and everything should
506 * be check for us... -A1kmm.
507 */
508 switch (server_check(name, source_p))
509 {
510 case -1:
511 if (ConfigGeneral.warn_no_connect_block)
512 {
513 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
514 "Unauthorized server connection attempt from %s: No entry for "
515 "servername %s", get_client_name(source_p, SHOW_IP), name);
516
517 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
518 "Unauthorized server connection attempt from %s: No entry for "
519 "servername %s", get_client_name(source_p, MASK_IP), name);
520 }
521
522 exit_client(source_p, "No connect {} block.");
523 return 0;
524 /* NOT REACHED */
525 break;
526
527 case -2:
528 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
529 "Unauthorized server connection attempt from %s: Bad password "
530 "for server %s", get_client_name(source_p, SHOW_IP), name);
531
532 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
533 "Unauthorized server connection attempt from %s: Bad password "
534 "for server %s", get_client_name(source_p, MASK_IP), name);
535
536 exit_client(source_p, "Invalid password.");
537 return 0;
538 /* NOT REACHED */
539 break;
540
541 case -3:
542 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
543 "Unauthorized server connection attempt from %s: Invalid host "
544 "for server %s", get_client_name(source_p, SHOW_IP), name);
545
546 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
547 "Unauthorized server connection attempt from %s: Invalid host "
548 "for server %s", get_client_name(source_p, MASK_IP), name);
549
550 exit_client(source_p, "Invalid host.");
551 return 0;
552 case -4:
553 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
554 "Unauthorized server connection attempt from %s: Invalid certificate fingerprint "
555 "for server %s", get_client_name(source_p, SHOW_IP), name);
556
557 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
558 "Unauthorized server connection attempt from %s: Invalid certificate fingerprint "
559 "for server %s", get_client_name(source_p, MASK_IP), name);
560
561 exit_client(source_p, "Invalid certificate fingerprint.");
562 return 0;
563 /* NOT REACHED */
564 break;
565 }
566
567 if ((target_p = hash_find_server(name)))
568 {
569 /* This link is trying feed me a server that I already have
570 * access through another path -- multiple paths not accepted
571 * currently, kill this link immediately!!
572 *
573 * Rather than KILL the link which introduced it, KILL the
574 * youngest of the two links. -avalon
575 *
576 * Definitely don't do that here. This is from an unregistered
577 * connect - A1kmm.
578 */
579 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
580 "Attempt to re-introduce server %s from %s",
581 name, get_client_name(source_p, SHOW_IP));
582 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
583 "Attempt to re-introduce server %s from %s",
584 name, get_client_name(source_p, MASK_IP));
585 exit_client(source_p, "Server already exists");
586 return 0;
587 }
588
589 if ((target_p = hash_find_id(source_p->id)))
590 {
591 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
592 "Attempt to re-introduce server %s SID %s from %s",
593 name, source_p->id,
594 get_client_name(source_p, SHOW_IP));
595 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
596 "Attempt to re-introduce server %s SID %s from %s",
597 name, source_p->id,
598 get_client_name(source_p, MASK_IP));
599 exit_client(source_p, "Server ID already exists");
600 return 0;
601 }
602
603 /* XXX If somehow there is a connect in progress and
604 * a connect comes in with same name toss the pending one,
605 * but only if it's not the same client! - Dianora
606 */
607 if ((target_p = find_servconn_in_progress(name)))
608 if (target_p != source_p)
609 exit_client(target_p, "Overridden");
610
611 /* if we are connecting (Handshake), we already have the name from the
612 * connect{} block in source_p->name
613 */
614 strlcpy(source_p->name, name, sizeof(source_p->name));
615
616 if (parc == 6) /* TBR: compatibility 'mode' */
617 {
618 strlcpy(source_p->id, sid, sizeof(source_p->id));
619 strlcpy(source_p->info, parv[parc - 1], sizeof(source_p->info));
620 server_set_flags(source_p, parv[4]);
621 }
622 else
623 server_set_gecos(source_p, parv[parc - 1]);
624
625 source_p->hopcount = atoi(parv[2]);
626 server_estab(source_p);
627 return 0;
628 }
629
630 /* ms_sid()
631 * parv[0] = command
632 * parv[1] = servername
633 * parv[2] = hopcount
634 * parv[3] = sid of new server
635 * parv[4] = serverinfo
636 *
637 * 8.3.x+:
638 * parv[0] = command
639 * parv[1] = servername
640 * parv[2] = hopcount
641 * parv[3] = sid of new server
642 * parv[4] = string of flags starting with '+'
643 * parv[5] = serverinfo
644 */
645 static int
646 ms_sid(struct Client *source_p, int parc, char *parv[])
647 {
648 dlink_node *node = NULL;
649 struct Client *target_p = NULL;
650 struct Client *client_p = source_p->from; /* XXX */
651 const struct MaskItem *conf = NULL;
652 int hlined = 0;
653 int llined = 0;
654
655 /* Just to be sure -A1kmm. */
656 if (!IsServer(source_p))
657 return 0;
658
659 if (EmptyString(parv[parc - 1]))
660 {
661 exit_client(client_p, "No server description supplied");
662 return 0;
663 }
664
665 if (!valid_servname(parv[1]))
666 {
667 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
668 "Link %s introduced server with bogus server name %s",
669 get_client_name(client_p, SHOW_IP), parv[1]);
670 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
671 "Link %s introduced server with bogus server name %s",
672 get_client_name(client_p, MASK_IP), parv[1]);
673 exit_client(client_p, "Bogus server name introduced");
674 return 0;
675 }
676
677 if (!valid_sid(parv[3]))
678 {
679 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
680 "Link %s introduced server with bogus server ID %s",
681 get_client_name(client_p, SHOW_IP), parv[3]);
682 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
683 "Link %s introduced server with bogus server ID %s",
684 get_client_name(client_p, MASK_IP), parv[3]);
685 exit_client(client_p, "Bogus server ID introduced");
686 return 0;
687 }
688
689 /* collision on SID? */
690 if ((target_p = hash_find_id(parv[3])))
691 {
692 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
693 "Link %s cancelled, server ID %s already exists",
694 get_client_name(client_p, SHOW_IP), parv[3]);
695 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
696 "Link %s cancelled, server ID %s already exists",
697 get_client_name(client_p, MASK_IP), parv[3]);
698 exit_client(client_p, "Link cancelled, server ID already exists");
699 return 0;
700 }
701
702 /* collision on name? */
703 if ((target_p = hash_find_server(parv[1])))
704 {
705 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
706 "Link %s cancelled, server %s already exists",
707 get_client_name(client_p, SHOW_IP), parv[1]);
708 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
709 "Link %s cancelled, server %s already exists",
710 get_client_name(client_p, MASK_IP), parv[1]);
711 exit_client(client_p, "Server exists");
712 return 0;
713 }
714
715 /* XXX If somehow there is a connect in progress and
716 * a connect comes in with same name toss the pending one,
717 * but only if it's not the same client! - Dianora
718 */
719 if ((target_p = find_servconn_in_progress(parv[1])))
720 if (target_p != client_p)
721 exit_client(target_p, "Overridden");
722
723 conf = client_p->connection->confs.head->data;
724
725 /* See if the newly found server is behind a guaranteed
726 * leaf. If so, close the link.
727 */
728 DLINK_FOREACH(node, conf->leaf_list.head)
729 {
730 if (!match(node->data, parv[1]))
731 {
732 llined = 1;
733 break;
734 }
735 }
736
737 DLINK_FOREACH(node, conf->hub_list.head)
738 {
739 if (!match(node->data, parv[1]))
740 {
741 hlined = 1;
742 break;
743 }
744 }
745
746 /* Ok, this way this works is
747 *
748 * A server can have a CONF_HUB allowing it to introduce servers
749 * behind it.
750 *
751 * connect {
752 * name = "irc.bighub.net";
753 * hub_mask="*";
754 * ...
755 *
756 * That would allow "irc.bighub.net" to introduce anything it wanted..
757 *
758 * However
759 *
760 * connect {
761 * name = "irc.somehub.fi";
762 * hub_mask="*";
763 * leaf_mask="*.edu";
764 *...
765 * Would allow this server in finland to hub anything but
766 * .edu's
767 */
768
769 /* Ok, check client_p can hub the new server, and make sure it's not a LL */
770 if (!hlined)
771 {
772 /* OOOPs nope can't HUB */
773 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
774 "Non-Hub link %s introduced %s.",
775 get_client_name(client_p, SHOW_IP), parv[1]);
776 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
777 "Non-Hub link %s introduced %s.",
778 get_client_name(client_p, MASK_IP), parv[1]);
779 exit_client(source_p, "No matching hub_mask.");
780 return 0;
781 }
782
783 /* Check for the new server being leafed behind this HUB */
784 if (llined)
785 {
786 /* OOOPs nope can't HUB this leaf */
787 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
788 "Link %s introduced leafed server %s.",
789 get_client_name(client_p, SHOW_IP), parv[1]);
790 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
791 "Link %s introduced leafed server %s.",
792 get_client_name(client_p, MASK_IP), parv[1]);
793 exit_client(client_p, "Leafed server.");
794 return 0;
795 }
796
797 target_p = client_make(client_p);
798 make_server(target_p);
799 target_p->hopcount = atoi(parv[2]);
800 target_p->servptr = source_p;
801
802 strlcpy(target_p->name, parv[1], sizeof(target_p->name));
803 strlcpy(target_p->id, parv[3], sizeof(target_p->id));
804
805 if (parc == 6) /* TBR: compatibility 'mode' */
806 {
807 strlcpy(target_p->info, parv[parc - 1], sizeof(target_p->info));
808 server_set_flags(target_p, parv[4]);
809 }
810 else
811 server_set_gecos(target_p, parv[parc - 1]);
812
813 SetServer(target_p);
814
815 if (service_find(target_p->name))
816 AddFlag(target_p, FLAGS_SERVICE);
817
818 dlinkAdd(target_p, &target_p->node, &global_server_list);
819 dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->server_list);
820
821 hash_add_client(target_p);
822 hash_add_id(target_p);
823
824 sendto_server(client_p, 0, 0, ":%s SID %s %u %s :%s%s",
825 source_p->id, target_p->name, target_p->hopcount + 1,
826 target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
827 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
828 "Server %s being introduced by %s",
829 target_p->name, source_p->name);
830 return 0;
831 }
832
833 static struct Message server_msgtab =
834 {
835 .cmd = "SERVER",
836 .args_min = 4,
837 .args_max = MAXPARA,
838 .handlers[UNREGISTERED_HANDLER] = mr_server,
839 .handlers[CLIENT_HANDLER] = m_registered,
840 .handlers[SERVER_HANDLER] = m_ignore,
841 .handlers[ENCAP_HANDLER] = m_ignore,
842 .handlers[OPER_HANDLER] = m_registered
843 };
844
845 static struct Message sid_msgtab =
846 {
847 .cmd = "SID",
848 .args_min = 5,
849 .args_max = MAXPARA,
850 .handlers[UNREGISTERED_HANDLER] = m_ignore,
851 .handlers[CLIENT_HANDLER] = m_ignore,
852 .handlers[SERVER_HANDLER] = ms_sid,
853 .handlers[ENCAP_HANDLER] = m_ignore,
854 .handlers[OPER_HANDLER] = m_ignore
855 };
856
857 static void
858 module_init(void)
859 {
860 mod_add_cmd(&sid_msgtab);
861 mod_add_cmd(&server_msgtab);
862 }
863
864 static void
865 module_exit(void)
866 {
867 mod_del_cmd(&sid_msgtab);
868 mod_del_cmd(&server_msgtab);
869 }
870
871 struct module module_entry =
872 {
873 .version = "$Revision$",
874 .modinit = module_init,
875 .modexit = module_exit,
876 .flags = MODULE_FLAG_CORE
877 };

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision