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: 8004
Committed: Tue Mar 14 14:32:25 2017 UTC (7 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 27744 byte(s)
Log Message:
- m_server.c: stylistic changes

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

Properties

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