ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_server.c
Revision: 7966
Committed: Mon Mar 13 19:09:33 2017 UTC (7 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 27500 byte(s)
Log Message:
- Get rid of Count.myserver

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 dlinkAdd(client_p, &client_p->node, &global_server_list);
270 hash_add_client(client_p);
271 hash_add_id(client_p);
272
273 /* Doesn't duplicate client_p->serv if allocated this struct already */
274 make_server(client_p);
275
276 /* Fixing eob timings.. -gnp */
277 client_p->connection->firsttime = CurrentTime;
278
279 if (service_find(client_p->name))
280 AddFlag(client_p, FLAGS_SERVICE);
281
282 /* Show the real host/IP to admins */
283 if (tls_isusing(&client_p->connection->fd.ssl))
284 {
285 /* Show the real host/IP to admins */
286 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
287 "Link with %s established: [TLS: %s] (Capabilities: %s)",
288 get_client_name(client_p, SHOW_IP), tls_get_cipher(&client_p->connection->fd.ssl),
289 get_capabilities(client_p));
290
291 /* Now show the masked hostname/IP to opers */
292 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
293 "Link with %s established: [TLS: %s] (Capabilities: %s)",
294 get_client_name(client_p, MASK_IP), tls_get_cipher(&client_p->connection->fd.ssl),
295 get_capabilities(client_p));
296 ilog(LOG_TYPE_IRCD, "Link with %s established: [TLS: %s] (Capabilities: %s)",
297 get_client_name(client_p, SHOW_IP), tls_get_cipher(&client_p->connection->fd.ssl),
298 get_capabilities(client_p));
299 }
300 else
301 {
302 /* Show the real host/IP to admins */
303 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
304 "Link with %s established: (Capabilities: %s)",
305 get_client_name(client_p, SHOW_IP), get_capabilities(client_p));
306 /* Now show the masked hostname/IP to opers */
307 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
308 "Link with %s established: (Capabilities: %s)",
309 get_client_name(client_p, MASK_IP), get_capabilities(client_p));
310 ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)",
311 get_client_name(client_p, SHOW_IP), get_capabilities(client_p));
312 }
313
314 fd_note(&client_p->connection->fd, "Server: %s", client_p->name);
315
316 sendto_server(client_p, 0, 0, ":%s SID %s 2 %s :%s%s",
317 me.id, client_p->name, client_p->id,
318 IsHidden(client_p) ? "(H) " : "", client_p->info);
319
320 /*
321 * Pass on my client information to the new server
322 *
323 * First, pass only servers (idea is that if the link gets
324 * cancelled beacause the server was already there,
325 * there are no NICK's to be cancelled...). Of course,
326 * if cancellation occurs, all this info is sent anyway,
327 * and I guess the link dies when a read is attempted...? --msa
328 *
329 * Note: Link cancellation to occur at this point means
330 * that at least two servers from my fragment are building
331 * up connection this other fragment at the same time, it's
332 * a race condition, not the normal way of operation...
333 */
334 DLINK_FOREACH_PREV(node, global_server_list.tail)
335 {
336 struct Client *target_p = node->data;
337
338 /* target_p->from == target_p for target_p == client_p */
339 if (IsMe(target_p) || target_p->from == client_p)
340 continue;
341
342 sendto_one(client_p, ":%s SID %s %u %s :%s%s",
343 target_p->servptr->id, target_p->name, target_p->hopcount+1,
344 target_p->id, IsHidden(target_p) ? "(H) " : "",
345 target_p->info);
346 }
347
348 server_burst(client_p);
349
350 if (IsCapable(client_p, CAPAB_EOB))
351 {
352 DLINK_FOREACH_PREV(node, global_server_list.tail)
353 {
354 struct Client *target_p = node->data;
355
356 if (target_p->from == client_p)
357 continue;
358
359 if (IsMe(target_p) || HasFlag(target_p, FLAGS_EOB))
360 sendto_one(client_p, ":%s EOB", target_p->id);
361 }
362 }
363 }
364
365 /* set_server_gecos()
366 *
367 * input - pointer to client
368 * output - NONE
369 * side effects - servers gecos field is set
370 */
371 static void
372 server_set_gecos(struct Client *client_p, const char *info)
373 {
374 const char *s = info;
375
376 /* check for (H) which is a hidden server */
377 if (!strncmp(s, "(H) ", 4))
378 {
379 AddFlag(client_p, FLAGS_HIDDEN);
380 s = s + 4;
381 }
382
383 if (!EmptyString(s))
384 strlcpy(client_p->info, s, sizeof(client_p->info));
385 else
386 strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info));
387 }
388
389 static int
390 server_check(const char *name, struct Client *client_p)
391 {
392 dlink_node *node = NULL;
393 struct MaskItem *server_conf = NULL;
394 int error = -1;
395
396 assert(client_p);
397
398 /* Loop through looking for all possible connect items that might work */
399 DLINK_FOREACH(node, connect_items.head)
400 {
401 struct MaskItem *conf = node->data;
402
403 if (irccmp(name, conf->name))
404 continue;
405
406 error = -3;
407
408 if (!irccmp(conf->host, client_p->host) ||
409 !irccmp(conf->host, client_p->sockhost))
410 {
411 error = -2;
412
413 if (!match_conf_password(client_p->connection->password, conf))
414 return -2;
415
416 if (!EmptyString(conf->certfp))
417 if (EmptyString(client_p->certfp) || strcasecmp(client_p->certfp, conf->certfp))
418 return -4;
419
420 server_conf = conf;
421 }
422 }
423
424 if (server_conf == NULL)
425 return error;
426
427 attach_conf(client_p, server_conf);
428
429 switch (server_conf->aftype)
430 {
431 case AF_INET6:
432 {
433 const struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&server_conf->addr;
434
435 if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr))
436 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
437 break;
438 }
439 case AF_INET:
440 {
441 const struct sockaddr_in *v4 = (struct sockaddr_in *)&server_conf->addr;
442
443 if (v4->sin_addr.s_addr == INADDR_NONE)
444 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
445 break;
446 }
447 }
448
449 return 0;
450 }
451
452 /* mr_server()
453 * parv[0] = command
454 * parv[1] = servername
455 * parv[2] = hopcount
456 * parv[3] = serverinfo
457 *
458 * 8.3.x+:
459 * parv[0] = command
460 * parv[1] = servername
461 * parv[2] = hopcount
462 * parv[3] = sid
463 * parv[4] = string of flags starting with '+'
464 * parv[5] = serverinfo
465 */
466 static int
467 mr_server(struct Client *source_p, int parc, char *parv[])
468 {
469 const char *name = parv[1];
470 const char *sid = parc == 6 ? parv[3] : source_p->id; /* TBR: compatibility 'mode' */
471 struct Client *target_p = NULL;
472
473 if (EmptyString(parv[parc - 1]))
474 {
475 exit_client(source_p, "No server description supplied");
476 return 0;
477 }
478
479 if (!valid_servname(name))
480 {
481 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
482 "Unauthorized server connection attempt from %s: Bogus server name "
483 "for server %s", get_client_name(source_p, SHOW_IP), name);
484 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
485 "Unauthorized server connection attempt from %s: Bogus server name "
486 "for server %s", get_client_name(source_p, MASK_IP), name);
487 exit_client(source_p, "Bogus server name");
488 return 0;
489 }
490
491 if (!valid_sid(sid))
492 {
493 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
494 "Link %s introduced server with bogus server ID %s",
495 get_client_name(source_p, SHOW_IP), sid);
496 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
497 "Link %s introduced server with bogus server ID %s",
498 get_client_name(source_p, MASK_IP), sid);
499 exit_client(source_p, "Bogus server ID introduced");
500 return 0;
501 }
502
503 /* Now we just have to call server_check() and everything should
504 * be check for us... -A1kmm.
505 */
506 switch (server_check(name, source_p))
507 {
508 case -1:
509 if (ConfigGeneral.warn_no_connect_block)
510 {
511 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
512 "Unauthorized server connection attempt from %s: No entry for "
513 "servername %s", get_client_name(source_p, SHOW_IP), name);
514
515 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
516 "Unauthorized server connection attempt from %s: No entry for "
517 "servername %s", get_client_name(source_p, MASK_IP), name);
518 }
519
520 exit_client(source_p, "No connect {} block.");
521 return 0;
522 /* NOT REACHED */
523 break;
524
525 case -2:
526 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
527 "Unauthorized server connection attempt from %s: Bad password "
528 "for server %s", get_client_name(source_p, SHOW_IP), name);
529
530 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
531 "Unauthorized server connection attempt from %s: Bad password "
532 "for server %s", get_client_name(source_p, MASK_IP), name);
533
534 exit_client(source_p, "Invalid password.");
535 return 0;
536 /* NOT REACHED */
537 break;
538
539 case -3:
540 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
541 "Unauthorized server connection attempt from %s: Invalid host "
542 "for server %s", get_client_name(source_p, SHOW_IP), name);
543
544 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
545 "Unauthorized server connection attempt from %s: Invalid host "
546 "for server %s", get_client_name(source_p, MASK_IP), name);
547
548 exit_client(source_p, "Invalid host.");
549 return 0;
550 case -4:
551 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
552 "Unauthorized server connection attempt from %s: Invalid certificate fingerprint "
553 "for server %s", get_client_name(source_p, SHOW_IP), name);
554
555 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
556 "Unauthorized server connection attempt from %s: Invalid certificate fingerprint "
557 "for server %s", get_client_name(source_p, MASK_IP), name);
558
559 exit_client(source_p, "Invalid certificate fingerprint.");
560 return 0;
561 /* NOT REACHED */
562 break;
563 }
564
565 if ((target_p = hash_find_server(name)))
566 {
567 /* This link is trying feed me a server that I already have
568 * access through another path -- multiple paths not accepted
569 * currently, kill this link immediately!!
570 *
571 * Rather than KILL the link which introduced it, KILL the
572 * youngest of the two links. -avalon
573 *
574 * Definitely don't do that here. This is from an unregistered
575 * connect - A1kmm.
576 */
577 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
578 "Attempt to re-introduce server %s from %s",
579 name, get_client_name(source_p, SHOW_IP));
580 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
581 "Attempt to re-introduce server %s from %s",
582 name, get_client_name(source_p, MASK_IP));
583 exit_client(source_p, "Server already exists");
584 return 0;
585 }
586
587 if ((target_p = hash_find_id(source_p->id)))
588 {
589 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
590 "Attempt to re-introduce server %s SID %s from %s",
591 name, source_p->id,
592 get_client_name(source_p, SHOW_IP));
593 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
594 "Attempt to re-introduce server %s SID %s from %s",
595 name, source_p->id,
596 get_client_name(source_p, MASK_IP));
597 exit_client(source_p, "Server ID already exists");
598 return 0;
599 }
600
601 /* XXX If somehow there is a connect in progress and
602 * a connect comes in with same name toss the pending one,
603 * but only if it's not the same client! - Dianora
604 */
605 if ((target_p = find_servconn_in_progress(name)))
606 if (target_p != source_p)
607 exit_client(target_p, "Overridden");
608
609 /* if we are connecting (Handshake), we already have the name from the
610 * connect{} block in source_p->name
611 */
612 strlcpy(source_p->name, name, sizeof(source_p->name));
613
614 if (parc == 6) /* TBR: compatibility 'mode' */
615 {
616 strlcpy(source_p->id, sid, sizeof(source_p->id));
617 strlcpy(source_p->info, parv[parc - 1], sizeof(source_p->info));
618 server_set_flags(source_p, parv[4]);
619 }
620 else
621 server_set_gecos(source_p, parv[parc - 1]);
622
623 source_p->hopcount = atoi(parv[2]);
624 server_estab(source_p);
625 return 0;
626 }
627
628 /* ms_sid()
629 * parv[0] = command
630 * parv[1] = servername
631 * parv[2] = hopcount
632 * parv[3] = sid of new server
633 * parv[4] = serverinfo
634 *
635 * 8.3.x+:
636 * parv[0] = command
637 * parv[1] = servername
638 * parv[2] = hopcount
639 * parv[3] = sid of new server
640 * parv[4] = string of flags starting with '+'
641 * parv[5] = serverinfo
642 */
643 static int
644 ms_sid(struct Client *source_p, int parc, char *parv[])
645 {
646 dlink_node *node = NULL;
647 struct Client *target_p = NULL;
648 struct Client *client_p = source_p->from; /* XXX */
649 const struct MaskItem *conf = NULL;
650 int hlined = 0;
651 int llined = 0;
652
653 /* Just to be sure -A1kmm. */
654 if (!IsServer(source_p))
655 return 0;
656
657 if (EmptyString(parv[parc - 1]))
658 {
659 exit_client(client_p, "No server description supplied");
660 return 0;
661 }
662
663 if (!valid_servname(parv[1]))
664 {
665 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
666 "Link %s introduced server with bogus server name %s",
667 get_client_name(client_p, SHOW_IP), parv[1]);
668 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
669 "Link %s introduced server with bogus server name %s",
670 get_client_name(client_p, MASK_IP), parv[1]);
671 exit_client(client_p, "Bogus server name introduced");
672 return 0;
673 }
674
675 if (!valid_sid(parv[3]))
676 {
677 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
678 "Link %s introduced server with bogus server ID %s",
679 get_client_name(client_p, SHOW_IP), parv[3]);
680 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
681 "Link %s introduced server with bogus server ID %s",
682 get_client_name(client_p, MASK_IP), parv[3]);
683 exit_client(client_p, "Bogus server ID introduced");
684 return 0;
685 }
686
687 /* collision on SID? */
688 if ((target_p = hash_find_id(parv[3])))
689 {
690 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
691 "Link %s cancelled, server ID %s already exists",
692 get_client_name(client_p, SHOW_IP), parv[3]);
693 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
694 "Link %s cancelled, server ID %s already exists",
695 get_client_name(client_p, MASK_IP), parv[3]);
696 exit_client(client_p, "Link cancelled, server ID already exists");
697 return 0;
698 }
699
700 /* collision on name? */
701 if ((target_p = hash_find_server(parv[1])))
702 {
703 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
704 "Link %s cancelled, server %s already exists",
705 get_client_name(client_p, SHOW_IP), parv[1]);
706 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
707 "Link %s cancelled, server %s already exists",
708 get_client_name(client_p, MASK_IP), parv[1]);
709 exit_client(client_p, "Server exists");
710 return 0;
711 }
712
713 /* XXX If somehow there is a connect in progress and
714 * a connect comes in with same name toss the pending one,
715 * but only if it's not the same client! - Dianora
716 */
717 if ((target_p = find_servconn_in_progress(parv[1])))
718 if (target_p != client_p)
719 exit_client(target_p, "Overridden");
720
721 conf = client_p->connection->confs.head->data;
722
723 /* See if the newly found server is behind a guaranteed
724 * leaf. If so, close the link.
725 */
726 DLINK_FOREACH(node, conf->leaf_list.head)
727 {
728 if (!match(node->data, parv[1]))
729 {
730 llined = 1;
731 break;
732 }
733 }
734
735 DLINK_FOREACH(node, conf->hub_list.head)
736 {
737 if (!match(node->data, parv[1]))
738 {
739 hlined = 1;
740 break;
741 }
742 }
743
744 /* Ok, this way this works is
745 *
746 * A server can have a CONF_HUB allowing it to introduce servers
747 * behind it.
748 *
749 * connect {
750 * name = "irc.bighub.net";
751 * hub_mask="*";
752 * ...
753 *
754 * That would allow "irc.bighub.net" to introduce anything it wanted..
755 *
756 * However
757 *
758 * connect {
759 * name = "irc.somehub.fi";
760 * hub_mask="*";
761 * leaf_mask="*.edu";
762 *...
763 * Would allow this server in finland to hub anything but
764 * .edu's
765 */
766
767 /* Ok, check client_p can hub the new server, and make sure it's not a LL */
768 if (!hlined)
769 {
770 /* OOOPs nope can't HUB */
771 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
772 "Non-Hub link %s introduced %s.",
773 get_client_name(client_p, SHOW_IP), parv[1]);
774 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
775 "Non-Hub link %s introduced %s.",
776 get_client_name(client_p, MASK_IP), parv[1]);
777 exit_client(source_p, "No matching hub_mask.");
778 return 0;
779 }
780
781 /* Check for the new server being leafed behind this HUB */
782 if (llined)
783 {
784 /* OOOPs nope can't HUB this leaf */
785 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
786 "Link %s introduced leafed server %s.",
787 get_client_name(client_p, SHOW_IP), parv[1]);
788 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
789 "Link %s introduced leafed server %s.",
790 get_client_name(client_p, MASK_IP), parv[1]);
791 exit_client(client_p, "Leafed server.");
792 return 0;
793 }
794
795 target_p = client_make(client_p);
796 make_server(target_p);
797 target_p->hopcount = atoi(parv[2]);
798 target_p->servptr = source_p;
799
800 strlcpy(target_p->name, parv[1], sizeof(target_p->name));
801 strlcpy(target_p->id, parv[3], sizeof(target_p->id));
802
803 if (parc == 6) /* TBR: compatibility 'mode' */
804 {
805 strlcpy(target_p->info, parv[parc - 1], sizeof(target_p->info));
806 server_set_flags(target_p, parv[4]);
807 }
808 else
809 server_set_gecos(target_p, parv[parc - 1]);
810
811 SetServer(target_p);
812
813 if (service_find(target_p->name))
814 AddFlag(target_p, FLAGS_SERVICE);
815
816 dlinkAdd(target_p, &target_p->node, &global_server_list);
817 dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->server_list);
818
819 hash_add_client(target_p);
820 hash_add_id(target_p);
821
822 sendto_server(client_p, 0, 0, ":%s SID %s %u %s :%s%s",
823 source_p->id, target_p->name, target_p->hopcount + 1,
824 target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
825 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
826 "Server %s being introduced by %s",
827 target_p->name, source_p->name);
828 return 0;
829 }
830
831 static struct Message server_msgtab =
832 {
833 .cmd = "SERVER",
834 .args_min = 4,
835 .args_max = MAXPARA,
836 .handlers[UNREGISTERED_HANDLER] = mr_server,
837 .handlers[CLIENT_HANDLER] = m_registered,
838 .handlers[SERVER_HANDLER] = m_ignore,
839 .handlers[ENCAP_HANDLER] = m_ignore,
840 .handlers[OPER_HANDLER] = m_registered
841 };
842
843 static struct Message sid_msgtab =
844 {
845 .cmd = "SID",
846 .args_min = 5,
847 .args_max = MAXPARA,
848 .handlers[UNREGISTERED_HANDLER] = m_ignore,
849 .handlers[CLIENT_HANDLER] = m_ignore,
850 .handlers[SERVER_HANDLER] = ms_sid,
851 .handlers[ENCAP_HANDLER] = m_ignore,
852 .handlers[OPER_HANDLER] = m_ignore
853 };
854
855 static void
856 module_init(void)
857 {
858 mod_add_cmd(&sid_msgtab);
859 mod_add_cmd(&server_msgtab);
860 }
861
862 static void
863 module_exit(void)
864 {
865 mod_del_cmd(&sid_msgtab);
866 mod_del_cmd(&server_msgtab);
867 }
868
869 struct module module_entry =
870 {
871 .version = "$Revision$",
872 .modinit = module_init,
873 .modexit = module_exit,
874 .flags = MODULE_FLAG_CORE
875 };

Properties

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