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: 4008
Committed: Thu Jun 19 15:18:21 2014 UTC (9 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 27833 byte(s)
Log Message:
- m_server.c:server_estab(): SVINFO can be prefixed

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
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 "irc_string.h"
33 #include "ircd.h"
34 #include "numeric.h"
35 #include "conf.h"
36 #include "log.h"
37 #include "misc.h"
38 #include "server.h"
39 #include "user.h"
40 #include "send.h"
41 #include "parse.h"
42 #include "memory.h"
43 #include "modules.h"
44
45
46 /*
47 * send_tb
48 *
49 * inputs - pointer to Client
50 * - pointer to channel
51 * output - NONE
52 * side effects - Called on a server burst when
53 * server is CAP_TBURST capable
54 */
55 static void
56 send_tb(struct Client *client_p, struct Channel *chptr)
57 {
58 /*
59 * We may also send an empty topic here, but only if topic_time isn't 0,
60 * i.e. if we had a topic that got unset. This is required for syncing
61 * topics properly.
62 *
63 * Imagine the following scenario: Our downlink introduces a channel
64 * to us with a TS that is equal to ours, but the channel topic on
65 * their side got unset while the servers were in splitmode, which means
66 * their 'topic' is newer. They simply wanted to unset it, so we have to
67 * deal with it in a more sophisticated fashion instead of just resetting
68 * it to their old topic they had before. Read m_tburst.c:ms_tburst
69 * for further information -Michael
70 */
71 if (chptr->topic_time)
72 sendto_one(client_p, ":%s TBURST %lu %s %lu %s :%s", me.id,
73 (unsigned long)chptr->channelts, chptr->chname,
74 (unsigned long)chptr->topic_time,
75 chptr->topic_info,
76 chptr->topic);
77 }
78
79 /* sendnick_TS()
80 *
81 * inputs - client (server) to send nick towards
82 * - client to send nick for
83 * output - NONE
84 * side effects - NICK message is sent towards given client_p
85 */
86 static void
87 sendnick_TS(struct Client *client_p, struct Client *target_p)
88 {
89 char ubuf[IRCD_BUFSIZE] = "";
90
91 if (!IsClient(target_p))
92 return;
93
94 send_umode(NULL, target_p, 0, SEND_UMODES, ubuf);
95
96 if (ubuf[0] == '\0')
97 {
98 ubuf[0] = '+';
99 ubuf[1] = '\0';
100 }
101
102 if (IsCapable(client_p, CAP_SVS))
103 sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s %s :%s",
104 target_p->servptr->id,
105 target_p->name, target_p->hopcount + 1,
106 (unsigned long) target_p->tsinfo,
107 ubuf, target_p->username, target_p->host,
108 (MyClient(target_p) && IsIPSpoof(target_p)) ?
109 "0" : target_p->sockhost, target_p->id,
110 target_p->svid, target_p->info);
111 else
112 sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s :%s",
113 target_p->servptr->id,
114 target_p->name, target_p->hopcount + 1,
115 (unsigned long) target_p->tsinfo,
116 ubuf, target_p->username, target_p->host,
117 (MyClient(target_p) && IsIPSpoof(target_p)) ?
118 "0" : target_p->sockhost, target_p->id, target_p->info);
119
120 if (!EmptyString(target_p->certfp))
121 sendto_one(client_p, ":%s CERTFP %s", target_p->id, target_p->certfp);
122
123 if (target_p->away[0])
124 sendto_one(client_p, ":%s AWAY :%s", target_p->id, target_p->away);
125
126 }
127
128 /* burst_members()
129 *
130 * inputs - pointer to server to send members to
131 * - dlink_list pointer to membership list to send
132 * output - NONE
133 * side effects -
134 */
135 static void
136 burst_members(struct Client *client_p, struct Channel *chptr)
137 {
138 struct Client *target_p;
139 struct Membership *ms;
140 dlink_node *ptr;
141
142 DLINK_FOREACH(ptr, chptr->members.head)
143 {
144 ms = ptr->data;
145 target_p = ms->client_p;
146
147 if (!HasFlag(target_p, FLAGS_BURSTED))
148 {
149 AddFlag(target_p, FLAGS_BURSTED);
150
151 if (target_p->from != client_p)
152 sendnick_TS(client_p, target_p);
153 }
154 }
155 }
156
157 /* burst_all()
158 *
159 * inputs - pointer to server to send burst to
160 * output - NONE
161 * side effects - complete burst of channels/nicks is sent to client_p
162 */
163 static void
164 burst_all(struct Client *client_p)
165 {
166 dlink_node *ptr = NULL;
167
168 DLINK_FOREACH(ptr, channel_list.head)
169 {
170 struct Channel *chptr = ptr->data;
171
172 if (dlink_list_length(&chptr->members))
173 {
174 burst_members(client_p, chptr);
175 send_channel_modes(client_p, chptr);
176
177 if (IsCapable(client_p, CAP_TBURST))
178 send_tb(client_p, chptr);
179 }
180 }
181
182 /* also send out those that are not on any channel
183 */
184 DLINK_FOREACH(ptr, global_client_list.head)
185 {
186 struct Client *target_p = ptr->data;
187
188 if (!HasFlag(target_p, FLAGS_BURSTED) && target_p->from != client_p)
189 sendnick_TS(client_p, target_p);
190
191 DelFlag(target_p, FLAGS_BURSTED);
192 }
193
194 if (IsCapable(client_p, CAP_EOB))
195 sendto_one(client_p, ":%s EOB", me.id);
196 }
197
198 /* server_burst()
199 *
200 * inputs - struct Client pointer server
201 * -
202 * output - none
203 * side effects - send a server burst
204 * bugs - still too long
205 */
206 static void
207 server_burst(struct Client *client_p)
208 {
209 /* Send it in the shortened format with the TS, if
210 ** it's a TS server; walk the list of channels, sending
211 ** all the nicks that haven't been sent yet for each
212 ** channel, then send the channel itself -- it's less
213 ** obvious than sending all nicks first, but on the
214 ** receiving side memory will be allocated more nicely
215 ** saving a few seconds in the handling of a split
216 ** -orabidoo
217 */
218
219 burst_all(client_p);
220
221 /* EOB stuff is now in burst_all */
222 /* Always send a PING after connect burst is done */
223 sendto_one(client_p, "PING :%s", me.id);
224 }
225
226 /* server_estab()
227 *
228 * inputs - pointer to a struct Client
229 * output -
230 * side effects -
231 */
232 static void
233 server_estab(struct Client *client_p)
234 {
235 struct MaskItem *conf = NULL;
236 char *host;
237 const char *inpath;
238 static char inpath_ip[HOSTLEN * 2 + USERLEN + 6];
239 dlink_node *ptr;
240 #ifdef HAVE_LIBCRYPTO
241 const COMP_METHOD *compression = NULL, *expansion = NULL;
242 #endif
243
244 assert(client_p);
245
246 strlcpy(inpath_ip, get_client_name(client_p, SHOW_IP), sizeof(inpath_ip));
247
248 inpath = get_client_name(client_p, MASK_IP); /* "refresh" inpath with host */
249 host = client_p->name;
250
251 if ((conf = find_conf_name(&client_p->localClient->confs, host, CONF_SERVER))
252 == NULL)
253 {
254 /* This shouldn't happen, better tell the ops... -A1kmm */
255 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
256 "Warning: Lost connect{} block "
257 "for server %s(this shouldn't happen)!", host);
258 exit_client(client_p, "Lost connect{} block!");
259 return;
260 }
261
262 MyFree(client_p->localClient->passwd);
263 client_p->localClient->passwd = NULL;
264
265 /* Its got identd, since its a server */
266 SetGotId(client_p);
267
268 /* If there is something in the serv_list, it might be this
269 * connecting server..
270 */
271 if (!ServerInfo.hub && serv_list.head)
272 {
273 if (client_p != serv_list.head->data || serv_list.head->next)
274 {
275 ++ServerStats.is_ref;
276 sendto_one(client_p, "ERROR :I'm a leaf not a hub");
277 exit_client(client_p, "I'm a leaf");
278 return;
279 }
280 }
281
282 if (IsUnknown(client_p))
283 {
284 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
285
286 send_capabilities(client_p, 0);
287
288 sendto_one(client_p, "SERVER %s 1 :%s%s",
289 me.name, ConfigServerHide.hidden ? "(H) " : "", me.info);
290 }
291
292 sendto_one(client_p, ":%s SVINFO %d %d 0 :%lu", me.id, TS_CURRENT, TS_MIN,
293 (unsigned long)CurrentTime);
294
295 /* XXX Does this ever happen? I don't think so -db */
296 detach_conf(client_p, CONF_OPER);
297
298 /* *WARNING*
299 ** In the following code in place of plain server's
300 ** name we send what is returned by get_client_name
301 ** which may add the "sockhost" after the name. It's
302 ** *very* *important* that there is a SPACE between
303 ** the name and sockhost (if present). The receiving
304 ** server will start the information field from this
305 ** first blank and thus puts the sockhost into info.
306 ** ...a bit tricky, but you have been warned, besides
307 ** code is more neat this way... --msa
308 */
309 client_p->servptr = &me;
310
311 if (IsClosing(client_p))
312 return;
313
314 SetServer(client_p);
315
316 /* Some day, all these lists will be consolidated *sigh* */
317 dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
318
319 assert(dlinkFind(&unknown_list, client_p));
320
321 dlink_move_node(&client_p->localClient->lclient_node,
322 &unknown_list, &serv_list);
323
324 Count.myserver++;
325
326 dlinkAdd(client_p, make_dlink_node(), &global_serv_list);
327 hash_add_client(client_p);
328 hash_add_id(client_p);
329
330 /* doesnt duplicate client_p->serv if allocated this struct already */
331 make_server(client_p);
332
333 /* fixing eob timings.. -gnp */
334 client_p->localClient->firsttime = CurrentTime;
335
336 if (find_matching_name_conf(CONF_SERVICE, client_p->name, NULL, NULL, 0))
337 AddFlag(client_p, FLAGS_SERVICE);
338
339 /* Show the real host/IP to admins */
340 #ifdef HAVE_LIBCRYPTO
341 if (client_p->localClient->fd.ssl)
342 {
343 compression = SSL_get_current_compression(client_p->localClient->fd.ssl);
344 expansion = SSL_get_current_expansion(client_p->localClient->fd.ssl);
345
346 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
347 "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
348 inpath_ip, ssl_get_cipher(client_p->localClient->fd.ssl),
349 compression ? SSL_COMP_get_name(compression) : "NONE",
350 expansion ? SSL_COMP_get_name(expansion) : "NONE",
351 show_capabilities(client_p));
352 /* Now show the masked hostname/IP to opers */
353 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
354 "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
355 inpath, ssl_get_cipher(client_p->localClient->fd.ssl),
356 compression ? SSL_COMP_get_name(compression) : "NONE",
357 expansion ? SSL_COMP_get_name(expansion) : "NONE",
358 show_capabilities(client_p));
359 ilog(LOG_TYPE_IRCD, "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
360 inpath_ip, ssl_get_cipher(client_p->localClient->fd.ssl),
361 compression ? SSL_COMP_get_name(compression) : "NONE",
362 expansion ? SSL_COMP_get_name(expansion) : "NONE",
363 show_capabilities(client_p));
364 }
365 else
366 #endif
367 {
368 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
369 "Link with %s established: (Capabilities: %s)",
370 inpath_ip, show_capabilities(client_p));
371 /* Now show the masked hostname/IP to opers */
372 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
373 "Link with %s established: (Capabilities: %s)",
374 inpath, show_capabilities(client_p));
375 ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)",
376 inpath_ip, show_capabilities(client_p));
377 }
378
379 fd_note(&client_p->localClient->fd, "Server: %s", client_p->name);
380
381 sendto_server(client_p, NOCAPS, NOCAPS, ":%s SID %s 2 %s :%s%s",
382 me.id, client_p->name, client_p->id,
383 IsHidden(client_p) ? "(H) " : "", client_p->info);
384
385 /*
386 * Pass on my client information to the new server
387 *
388 * First, pass only servers (idea is that if the link gets
389 * cancelled beacause the server was already there,
390 * there are no NICK's to be cancelled...). Of course,
391 * if cancellation occurs, all this info is sent anyway,
392 * and I guess the link dies when a read is attempted...? --msa
393 *
394 * Note: Link cancellation to occur at this point means
395 * that at least two servers from my fragment are building
396 * up connection this other fragment at the same time, it's
397 * a race condition, not the normal way of operation...
398 *
399 * ALSO NOTE: using the get_client_name for server names--
400 * see previous *WARNING*!!! (Also, original inpath
401 * is destroyed...)
402 */
403 DLINK_FOREACH_PREV(ptr, global_serv_list.tail)
404 {
405 struct Client *target_p = ptr->data;
406
407 /* target_p->from == target_p for target_p == client_p */
408 if (IsMe(target_p) || target_p->from == client_p)
409 continue;
410
411 sendto_one(client_p, ":%s SID %s %d %s :%s%s",
412 target_p->servptr->id, target_p->name, target_p->hopcount+1,
413 target_p->id, IsHidden(target_p) ? "(H) " : "",
414 target_p->info);
415 }
416
417 server_burst(client_p);
418 }
419
420 /* set_server_gecos()
421 *
422 * input - pointer to client
423 * output - NONE
424 * side effects - servers gecos field is set
425 */
426 static void
427 set_server_gecos(struct Client *client_p, const char *info)
428 {
429 const char *s = info;
430
431 /* check for (H) which is a hidden server */
432 if (!strncmp(s, "(H) ", 4))
433 {
434 SetHidden(client_p);
435 s = s + 4;
436 }
437
438 if (!EmptyString(s))
439 strlcpy(client_p->info, s, sizeof(client_p->info));
440 else
441 strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info));
442 }
443
444 /* mr_server()
445 * parv[0] = command
446 * parv[1] = servername
447 * parv[2] = hopcount
448 * parv[3] = serverinfo
449 */
450 static int
451 mr_server(struct Client *source_p, int parc, char *parv[])
452 {
453 char *name = NULL;
454 struct Client *target_p = NULL;
455
456 if (EmptyString(parv[3]))
457 {
458 sendto_one(source_p, "ERROR :No servername");
459 exit_client(source_p, "Wrong number of args");
460 return 0;
461 }
462
463 name = parv[1];
464
465 /*
466 * Reject a direct nonTS server connection if we're TS_ONLY -orabidoo
467 */
468 if (!DoesTS(source_p))
469 {
470 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
471 "Unauthorized server connection attempt from %s: Non-TS server "
472 "for server %s", get_client_name(source_p, HIDE_IP), name);
473 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
474 "Unauthorized server connection attempt from %s: Non-TS server "
475 "for server %s", get_client_name(source_p, MASK_IP), name);
476 exit_client(source_p, "Non-TS server");
477 return 0;
478 }
479
480 if (!valid_servname(name))
481 {
482 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
483 "Unauthorized server connection attempt from %s: Bogus server name "
484 "for server %s", get_client_name(source_p, HIDE_IP), name);
485 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
486 "Unauthorized server connection attempt from %s: Bogus server name "
487 "for server %s", get_client_name(source_p, MASK_IP), name);
488 exit_client(source_p, "Bogus server name");
489 return 0;
490 }
491
492 if (!valid_sid(source_p->id))
493 {
494 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
495 "Link %s introduced server with bogus server ID %s",
496 get_client_name(source_p, SHOW_IP), source_p->id);
497 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
498 "Link %s introduced server with bogus server ID %s",
499 get_client_name(source_p, MASK_IP), source_p->id);
500 sendto_one(source_p, "ERROR :Bogus server ID introduced");
501 exit_client(source_p, "Bogus server ID intoduced");
502 return 0;
503 }
504
505 /* Now we just have to call check_server and everything should
506 * be check for us... -A1kmm.
507 */
508 switch (check_server(name, source_p))
509 {
510 case -1:
511 if (ConfigFileEntry.warn_no_connect_block)
512 {
513 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
514 "Unauthorized server connection attempt from %s: No entry for "
515 "servername %s", get_client_name(source_p, HIDE_IP), name);
516
517 sendto_realops_flags(UMODE_ALL, 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_ALL, L_ADMIN, SEND_NOTICE,
529 "Unauthorized server connection attempt from %s: Bad password "
530 "for server %s", get_client_name(source_p, HIDE_IP), name);
531
532 sendto_realops_flags(UMODE_ALL, 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_ALL, L_ADMIN, SEND_NOTICE,
543 "Unauthorized server connection attempt from %s: Invalid host "
544 "for server %s", get_client_name(source_p, HIDE_IP), name);
545
546 sendto_realops_flags(UMODE_ALL, 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_ALL, L_ADMIN, SEND_NOTICE,
554 "Unauthorized server connection attempt from %s: Invalid certificate fingerprint "
555 "for server %s", get_client_name(source_p, HIDE_IP), name);
556
557 sendto_realops_flags(UMODE_ALL, 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_ALL, L_ADMIN, SEND_NOTICE,
580 "Attempt to re-introduce server %s from %s",
581 name, get_client_name(source_p, HIDE_IP));
582 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
583 "Attempt to re-introduce server %s from %s",
584 name, get_client_name(source_p, MASK_IP));
585 sendto_one(source_p, "ERROR :Server already exists.");
586 exit_client(source_p, "Server already exists");
587 return 0;
588 }
589
590 if ((target_p = hash_find_id(source_p->id)))
591 {
592 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
593 "Attempt to re-introduce server %s SID %s from %s",
594 name, source_p->id,
595 get_client_name(source_p, HIDE_IP));
596 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
597 "Attempt to re-introduce server %s SID %s from %s",
598 name, source_p->id,
599 get_client_name(source_p, MASK_IP));
600 sendto_one(source_p, "ERROR :Server ID already exists.");
601 exit_client(source_p, "Server ID already exists");
602 return 0;
603 }
604
605 /* XXX If somehow there is a connect in progress and
606 * a connect comes in with same name toss the pending one,
607 * but only if it's not the same client! - Dianora
608 */
609 if ((target_p = find_servconn_in_progress(name)))
610 if (target_p != source_p)
611 exit_client(target_p, "Overridden");
612
613 /* if we are connecting (Handshake), we already have the name from the
614 * connect{} block in source_p->name
615 */
616 strlcpy(source_p->name, name, sizeof(source_p->name));
617 set_server_gecos(source_p, parv[3]);
618 source_p->hopcount = atoi(parv[2]);
619 server_estab(source_p);
620 return 0;
621 }
622
623 /* ms_sid()
624 * parv[0] = command
625 * parv[1] = servername
626 * parv[2] = hopcount
627 * parv[3] = sid of new server
628 * parv[4] = serverinfo
629 */
630 static int
631 ms_sid(struct Client *source_p, int parc, char *parv[])
632 {
633 dlink_node *ptr = NULL;
634 struct Client *target_p = NULL;
635 struct Client *client_p = source_p->from; /* XXX */
636 const struct MaskItem *conf = NULL;
637 int hlined = 0;
638 int llined = 0;
639
640 /* Just to be sure -A1kmm. */
641 if (!IsServer(source_p))
642 return 0;
643
644 if (EmptyString(parv[4]))
645 {
646 sendto_one(client_p, "ERROR :No servername");
647 return 0;
648 }
649
650 if (!valid_servname(parv[1]))
651 {
652 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
653 "Link %s introduced server with bogus server name %s",
654 get_client_name(client_p, SHOW_IP), parv[1]);
655 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
656 "Link %s introduced server with bogus server name %s",
657 get_client_name(client_p, MASK_IP), parv[1]);
658 sendto_one(client_p, "ERROR :Bogus server name introduced");
659 exit_client(client_p, "Bogus server name intoduced");
660 return 0;
661 }
662
663 if (!valid_sid(parv[3]))
664 {
665 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
666 "Link %s introduced server with bogus server ID %s",
667 get_client_name(client_p, SHOW_IP), parv[3]);
668 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
669 "Link %s introduced server with bogus server ID %s",
670 get_client_name(client_p, MASK_IP), parv[3]);
671 sendto_one(client_p, "ERROR :Bogus server ID introduced");
672 exit_client(client_p, "Bogus server ID intoduced");
673 return 0;
674 }
675
676 /* collision on SID? */
677 if ((target_p = hash_find_id(parv[3])))
678 {
679 sendto_one(client_p, "ERROR :SID %s already exists", parv[3]);
680 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
681 "Link %s cancelled, SID %s already exists",
682 get_client_name(client_p, SHOW_IP), parv[3]);
683 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
684 "Link %s cancelled, SID %s already exists",
685 client_p->name, parv[3]);
686 exit_client(client_p, "SID Exists");
687 return 0;
688 }
689
690 /* collision on name? */
691 if ((target_p = hash_find_server(parv[1])))
692 {
693 sendto_one(client_p, "ERROR :Server %s already exists", parv[1]);
694 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
695 "Link %s cancelled, server %s already exists",
696 get_client_name(client_p, SHOW_IP), parv[1]);
697 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
698 "Link %s cancelled, server %s already exists",
699 client_p->name, parv[1]);
700 exit_client(client_p, "Server Exists");
701 return 0;
702 }
703
704 /* XXX If somehow there is a connect in progress and
705 * a connect comes in with same name toss the pending one,
706 * but only if it's not the same client! - Dianora
707 */
708 if ((target_p = find_servconn_in_progress(parv[1])))
709 if (target_p != client_p)
710 exit_client(target_p, "Overridden");
711
712 conf = client_p->localClient->confs.head->data;
713
714 /* See if the newly found server is behind a guaranteed
715 * leaf. If so, close the link.
716 */
717 DLINK_FOREACH(ptr, conf->leaf_list.head)
718 {
719 if (!match(ptr->data, parv[1]))
720 {
721 llined = 1;
722 break;
723 }
724 }
725
726 DLINK_FOREACH(ptr, conf->hub_list.head)
727 {
728 if (!match(ptr->data, parv[1]))
729 {
730 hlined = 1;
731 break;
732 }
733 }
734
735 /* Ok, this way this works is
736 *
737 * A server can have a CONF_HUB allowing it to introduce servers
738 * behind it.
739 *
740 * connect {
741 * name = "irc.bighub.net";
742 * hub_mask="*";
743 * ...
744 *
745 * That would allow "irc.bighub.net" to introduce anything it wanted..
746 *
747 * However
748 *
749 * connect {
750 * name = "irc.somehub.fi";
751 * hub_mask="*";
752 * leaf_mask="*.edu";
753 *...
754 * Would allow this server in finland to hub anything but
755 * .edu's
756 */
757
758 /* Ok, check client_p can hub the new server, and make sure it's not a LL */
759 if (!hlined)
760 {
761 /* OOOPs nope can't HUB */
762 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
763 "Non-Hub link %s introduced %s.",
764 get_client_name(client_p, SHOW_IP), parv[1]);
765 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
766 "Non-Hub link %s introduced %s.",
767 get_client_name(client_p, MASK_IP), parv[1]);
768 exit_client(source_p, "No matching hub_mask.");
769 return 0;
770 }
771
772 /* Check for the new server being leafed behind this HUB */
773 if (llined)
774 {
775 /* OOOPs nope can't HUB this leaf */
776 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
777 "Link %s introduced leafed server %s.",
778 get_client_name(client_p, SHOW_IP), parv[1]);
779 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
780 "Link %s introduced leafed server %s.",
781 get_client_name(client_p, MASK_IP), parv[1]);
782 exit_client(client_p, "Leafed Server.");
783 return 0;
784 }
785
786 target_p = make_client(client_p);
787 make_server(target_p);
788 target_p->hopcount = atoi(parv[2]);
789 target_p->servptr = source_p;
790
791 strlcpy(target_p->name, parv[1], sizeof(target_p->name));
792 strlcpy(target_p->id, parv[3], sizeof(target_p->id));
793
794 set_server_gecos(target_p, parv[4]);
795 SetServer(target_p);
796
797 if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(CONF_SERVICE, target_p->name, NULL, NULL, 0))
798 AddFlag(target_p, FLAGS_SERVICE);
799
800 dlinkAdd(target_p, &target_p->node, &global_client_list);
801 dlinkAdd(target_p, make_dlink_node(), &global_serv_list);
802 dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->server_list);
803
804 hash_add_client(target_p);
805 hash_add_id(target_p);
806
807 sendto_server(client_p, NOCAPS, NOCAPS, ":%s SID %s %d %s :%s%s",
808 source_p->id, target_p->name, target_p->hopcount + 1,
809 target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
810 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
811 "Server %s being introduced by %s",
812 target_p->name, source_p->name);
813 return 0;
814 }
815
816 static struct Message server_msgtab =
817 {
818 "SERVER", 0, 0, 4, MAXPARA, MFLG_SLOW, 0,
819 { mr_server, m_registered, m_ignore, m_ignore, m_registered, m_ignore }
820 };
821
822 static struct Message sid_msgtab =
823 {
824 "SID", 0, 0, 5, MAXPARA, MFLG_SLOW, 0,
825 { m_ignore, m_ignore, ms_sid, m_ignore, m_ignore, m_ignore }
826 };
827
828 static void
829 module_init(void)
830 {
831 mod_add_cmd(&sid_msgtab);
832 mod_add_cmd(&server_msgtab);
833 }
834
835 static void
836 module_exit(void)
837 {
838 mod_del_cmd(&sid_msgtab);
839 mod_del_cmd(&server_msgtab);
840 }
841
842 struct module module_entry =
843 {
844 .node = { NULL, NULL, NULL },
845 .name = NULL,
846 .version = "$Revision$",
847 .handle = NULL,
848 .modinit = module_init,
849 .modexit = module_exit,
850 .flags = MODULE_FLAG_CORE
851 };

Properties

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