/[svn]/ircd-hybrid/branches/8.2.x/modules/core/m_server.c
ViewVC logotype

Contents of /ircd-hybrid/branches/8.2.x/modules/core/m_server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8495 - (show annotations)
Thu Apr 5 12:40:05 2018 UTC (5 years, 1 month ago) by michael
File MIME type: text/x-chdr
File size: 27701 byte(s)
- Killed userhost.c. Rewrote everything to use ipcache.c

1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2018 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 "client_svstag.h"
31 #include "event.h"
32 #include "hash.h"
33 #include "id.h"
34 #include "irc_string.h"
35 #include "ircd.h"
36 #include "numeric.h"
37 #include "conf.h"
38 #include "conf_service.h"
39 #include "log.h"
40 #include "misc.h"
41 #include "server.h"
42 #include "server_capab.h"
43 #include "user.h"
44 #include "send.h"
45 #include "parse.h"
46 #include "memory.h"
47 #include "modules.h"
48 #include "fdlist.h"
49
50
51 /*! Parses server flags to be potentially set
52 * \param client_p Pointer to server's Client structure
53 * \param flags Pointer to the flag string to be parsed
54 */
55 static void
56 server_set_flags(struct Client *client_p, const char *flags)
57 {
58 const unsigned char *p = (const unsigned char *)flags;
59
60 if (*p != '+')
61 return;
62
63 while (*++p)
64 {
65 switch (*p)
66 {
67 case 'h':
68 AddFlag(client_p, FLAGS_HIDDEN);
69 break;
70 default:
71 break;
72 }
73 }
74 }
75
76 /*
77 * send_tb
78 *
79 * inputs - pointer to Client
80 * - pointer to channel
81 * output - NONE
82 * side effects - Called on a server burst when
83 * server is CAPAB_TBURST capable
84 */
85 static void
86 server_send_tburst(struct Client *client_p, const struct Channel *chptr)
87 {
88 /*
89 * We may also send an empty topic here, but only if topic_time isn't 0,
90 * i.e. if we had a topic that got unset. This is required for syncing
91 * topics properly.
92 *
93 * Imagine the following scenario: Our downlink introduces a channel
94 * to us with a TS that is equal to ours, but the channel topic on
95 * their side got unset while the servers were in splitmode, which means
96 * their 'topic' is newer. They simply wanted to unset it, so we have to
97 * deal with it in a more sophisticated fashion instead of just resetting
98 * it to their old topic they had before. Read m_tburst.c:ms_tburst
99 * for further information -Michael
100 */
101 if (chptr->topic_time)
102 sendto_one(client_p, ":%s TBURST %ju %s %ju %s :%s", me.id,
103 chptr->creationtime, chptr->name,
104 chptr->topic_time,
105 chptr->topic_info,
106 chptr->topic);
107 }
108
109 /* sendnick_TS()
110 *
111 * inputs - client (server) to send nick towards
112 * - client to send nick for
113 * output - NONE
114 * side effects - NICK message is sent towards given client_p
115 */
116 static void
117 server_send_client(struct Client *client_p, struct Client *target_p)
118 {
119 dlink_node *node;
120 char buf[UMODE_MAX_STR] = "";
121
122 assert(IsClient(target_p));
123
124 send_umode(target_p, 0, 0, buf);
125
126 if (buf[0] == '\0')
127 {
128 buf[0] = '+';
129 buf[1] = '\0';
130 }
131
132 /* TBR: compatibility mode */
133 if (IsCapable(client_p, CAPAB_RHOST))
134 sendto_one(client_p, ":%s UID %s %u %ju %s %s %s %s %s %s %s :%s",
135 target_p->servptr->id,
136 target_p->name, target_p->hopcount + 1,
137 target_p->tsinfo,
138 buf, target_p->username, target_p->host, target_p->realhost,
139 target_p->sockhost, target_p->id,
140 target_p->account, target_p->info);
141 else
142 sendto_one(client_p, ":%s UID %s %u %ju %s %s %s %s %s %s :%s",
143 target_p->servptr->id,
144 target_p->name, target_p->hopcount + 1,
145 target_p->tsinfo,
146 buf, target_p->username, target_p->host,
147 target_p->sockhost, target_p->id,
148 target_p->account, target_p->info);
149
150 if (!EmptyString(target_p->certfp))
151 sendto_one(client_p, ":%s CERTFP %s", target_p->id, target_p->certfp);
152
153 if (target_p->away[0])
154 sendto_one(client_p, ":%s AWAY :%s", target_p->id, target_p->away);
155
156
157 DLINK_FOREACH(node, target_p->svstags.head)
158 {
159 const struct ServicesTag *svstag = node->data;
160 char *m = buf;
161
162 for (const struct user_modes *tab = umode_tab; tab->c; ++tab)
163 if (svstag->umodes & tab->flag)
164 *m++ = tab->c;
165 *m = '\0';
166
167 sendto_one(client_p, ":%s SVSTAG %s %ju %u +%s :%s", me.id, target_p->id,
168 target_p->tsinfo, svstag->numeric, buf, svstag->tag);
169 }
170 }
171
172 /* burst_all()
173 *
174 * inputs - pointer to server to send burst to
175 * output - NONE
176 * side effects - complete burst of channels/nicks is sent to client_p
177 */
178 static void
179 server_burst(struct Client *client_p)
180 {
181 dlink_node *node = NULL;
182
183 DLINK_FOREACH(node, global_client_list.head)
184 {
185 struct Client *target_p = node->data;
186
187 if (target_p->from != client_p)
188 server_send_client(client_p, target_p);
189 }
190
191 DLINK_FOREACH(node, channel_get_list()->head)
192 {
193 const struct Channel *chptr = node->data;
194
195 if (dlink_list_length(&chptr->members))
196 {
197 channel_send_modes(client_p, chptr);
198
199 if (IsCapable(client_p, CAPAB_TBURST))
200 server_send_tburst(client_p, chptr);
201 }
202 }
203
204 /* Always send a PING after connect burst is done */
205 sendto_one(client_p, "PING :%s", me.id);
206 }
207
208 /* server_estab()
209 *
210 * inputs - pointer to a struct Client
211 * output -
212 * side effects -
213 */
214 static void
215 server_estab(struct Client *client_p)
216 {
217 struct MaskItem *conf = NULL;
218 dlink_node *node = NULL;
219
220 if ((conf = find_conf_name(&client_p->connection->confs, client_p->name, CONF_SERVER)) == NULL)
221 {
222 /* This shouldn't happen, better tell the ops... -A1kmm */
223 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
224 "Warning: lost connect{} block for %s",
225 client_get_name(client_p, SHOW_IP));
226 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
227 "Warning: lost connect{} block for %s",
228 client_get_name(client_p, MASK_IP));
229 exit_client(client_p, "Lost connect{} block!");
230 return;
231 }
232
233 xfree(client_p->connection->password);
234 client_p->connection->password = NULL;
235
236 if (!ConfigServerInfo.hub && dlink_list_length(&local_server_list))
237 {
238 ++ServerStats.is_ref;
239 exit_client(client_p, "I'm a leaf not a hub");
240 return;
241 }
242
243 if (IsUnknown(client_p))
244 {
245 sendto_one(client_p, "PASS %s TS %u %s", conf->spasswd, TS_CURRENT, me.id);
246
247 sendto_one(client_p, "CAPAB :%s", capab_get(NULL));
248
249 sendto_one(client_p, "SERVER %s 1 :%s%s",
250 me.name, ConfigServerHide.hidden ? "(H) " : "", me.info);
251 }
252
253 sendto_one(client_p, ":%s SVINFO %u %u 0 :%ju", me.id, TS_CURRENT, TS_MIN,
254 CurrentTime);
255
256 client_p->servptr = &me;
257
258 if (HasFlag(client_p, FLAGS_CLOSING))
259 return;
260
261 SetServer(client_p);
262
263 dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
264
265 assert(dlinkFind(&unknown_list, client_p));
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 server_make(client_p);
281
282 /* Fixing eob timings.. -gnp */
283 client_p->connection->firsttime = CurrentTime;
284
285 if (service_find(client_p->name, irccmp))
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 capab_get(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 capab_get(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 capab_get(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), capab_get(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), capab_get(client_p));
316 ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)",
317 client_get_name(client_p, SHOW_IP), capab_get(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 conf_attach(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->ip, sizeof(server_conf->addr));
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->ip, sizeof(server_conf->addr));
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 (!server_valid_name(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
654 /* Just to be sure -A1kmm. */
655 if (!IsServer(source_p))
656 return 0;
657
658 if (EmptyString(parv[parc - 1]))
659 {
660 exit_client(source_p->from, "No server description supplied");
661 return 0;
662 }
663
664 if (!server_valid_name(parv[1]))
665 {
666 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
667 "Link %s introduced server with bogus server name %s",
668 client_get_name(source_p->from, SHOW_IP), parv[1]);
669 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
670 "Link %s introduced server with bogus server name %s",
671 client_get_name(source_p->from, MASK_IP), parv[1]);
672 exit_client(source_p->from, "Bogus server name introduced");
673 return 0;
674 }
675
676 if (!valid_sid(parv[3]))
677 {
678 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
679 "Link %s introduced server with bogus server ID %s",
680 client_get_name(source_p->from, SHOW_IP), parv[3]);
681 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
682 "Link %s introduced server with bogus server ID %s",
683 client_get_name(source_p->from, MASK_IP), parv[3]);
684 exit_client(source_p->from, "Bogus server ID introduced");
685 return 0;
686 }
687
688 /* collision on SID? */
689 if ((target_p = hash_find_id(parv[3])))
690 {
691 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
692 "Link %s cancelled, server ID %s already exists",
693 client_get_name(source_p->from, SHOW_IP), parv[3]);
694 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
695 "Link %s cancelled, server ID %s already exists",
696 client_get_name(source_p->from, MASK_IP), parv[3]);
697 exit_client(source_p->from, "Link cancelled, server ID already exists");
698 return 0;
699 }
700
701 /* collision on name? */
702 if ((target_p = hash_find_server(parv[1])))
703 {
704 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
705 "Link %s cancelled, server %s already exists",
706 client_get_name(source_p->from, SHOW_IP), parv[1]);
707 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
708 "Link %s cancelled, server %s already exists",
709 client_get_name(source_p->from, MASK_IP), parv[1]);
710 exit_client(source_p->from, "Server exists");
711 return 0;
712 }
713
714 /* XXX If somehow there is a connect in progress and
715 * a connect comes in with same name toss the pending one,
716 * but only if it's not the same client! - Dianora
717 */
718 if ((target_p = find_servconn_in_progress(parv[1])))
719 if (target_p != source_p->from)
720 exit_client(target_p, "Overridden");
721
722 /*
723 * See if the newly found server is behind a guaranteed
724 * leaf. If so, close the link.
725 */
726 dlink_node *node;
727 unsigned int hlined = 0;
728 unsigned int llined = 0;
729 const struct MaskItem *conf = source_p->from->connection->confs.head->data;
730
731 DLINK_FOREACH(node, conf->leaf_list.head)
732 {
733 if (!match(node->data, parv[1]))
734 {
735 llined = 1;
736 break;
737 }
738 }
739
740 DLINK_FOREACH(node, conf->hub_list.head)
741 {
742 if (!match(node->data, parv[1]))
743 {
744 hlined = 1;
745 break;
746 }
747 }
748
749 /* Ok, this way this works is
750 *
751 * A server can have a CONF_HUB allowing it to introduce servers
752 * behind it.
753 *
754 * connect {
755 * name = "irc.bighub.net";
756 * hub_mask="*";
757 * ...
758 *
759 * That would allow "irc.bighub.net" to introduce anything it wanted..
760 *
761 * However
762 *
763 * connect {
764 * name = "irc.somehub.fi";
765 * hub_mask="*";
766 * leaf_mask="*.edu";
767 *...
768 * Would allow this server in finland to hub anything but
769 * .edu's
770 */
771
772 /* Ok, check source_p->from can hub the new server */
773 if (!hlined)
774 {
775 /* OOOPs nope can't HUB */
776 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
777 "Non-Hub link %s introduced %s.",
778 client_get_name(source_p->from, SHOW_IP), parv[1]);
779 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
780 "Non-Hub link %s introduced %s.",
781 client_get_name(source_p->from, MASK_IP), parv[1]);
782 exit_client(source_p, "No matching hub_mask.");
783 return 0;
784 }
785
786 /* Check for the new server being leafed behind this HUB */
787 if (llined)
788 {
789 /* OOOPs nope can't HUB this leaf */
790 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
791 "Link %s introduced leafed server %s.",
792 client_get_name(source_p->from, SHOW_IP), parv[1]);
793 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
794 "Link %s introduced leafed server %s.",
795 client_get_name(source_p->from, MASK_IP), parv[1]);
796 exit_client(source_p->from, "Leafed server.");
797 return 0;
798 }
799
800 target_p = client_make(source_p->from);
801 server_make(target_p);
802 target_p->hopcount = atoi(parv[2]);
803 target_p->servptr = source_p;
804
805 strlcpy(target_p->name, parv[1], sizeof(target_p->name));
806 strlcpy(target_p->id, parv[3], sizeof(target_p->id));
807
808 if (parc == 6) /* TBR: compatibility 'mode' */
809 {
810 strlcpy(target_p->info, parv[parc - 1], sizeof(target_p->info));
811 server_set_flags(target_p, parv[4]);
812 }
813 else
814 server_set_gecos(target_p, parv[parc - 1]);
815
816 SetServer(target_p);
817
818 if (service_find(target_p->name, irccmp))
819 AddFlag(target_p, FLAGS_SERVICE);
820
821 dlinkAdd(target_p, &target_p->node, &global_server_list);
822 dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->server_list);
823
824 hash_add_client(target_p);
825 hash_add_id(target_p);
826
827 sendto_server(source_p->from, 0, 0, ":%s SID %s %u %s :%s%s",
828 source_p->id, target_p->name, target_p->hopcount + 1,
829 target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
830 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
831 "Server %s being introduced by %s",
832 target_p->name, source_p->name);
833 return 0;
834 }
835
836 static struct Message server_msgtab =
837 {
838 .cmd = "SERVER",
839 .args_min = 4,
840 .args_max = MAXPARA,
841 .handlers[UNREGISTERED_HANDLER] = mr_server,
842 .handlers[CLIENT_HANDLER] = m_registered,
843 .handlers[SERVER_HANDLER] = m_ignore,
844 .handlers[ENCAP_HANDLER] = m_ignore,
845 .handlers[OPER_HANDLER] = m_registered
846 };
847
848 static struct Message sid_msgtab =
849 {
850 .cmd = "SID",
851 .args_min = 5,
852 .args_max = MAXPARA,
853 .handlers[UNREGISTERED_HANDLER] = m_ignore,
854 .handlers[CLIENT_HANDLER] = m_ignore,
855 .handlers[SERVER_HANDLER] = ms_sid,
856 .handlers[ENCAP_HANDLER] = m_ignore,
857 .handlers[OPER_HANDLER] = m_ignore
858 };
859
860 static void
861 module_init(void)
862 {
863 mod_add_cmd(&sid_msgtab);
864 mod_add_cmd(&server_msgtab);
865 }
866
867 static void
868 module_exit(void)
869 {
870 mod_del_cmd(&sid_msgtab);
871 mod_del_cmd(&server_msgtab);
872 }
873
874 struct module module_entry =
875 {
876 .version = "$Revision$",
877 .modinit = module_init,
878 .modexit = module_exit,
879 .flags = MODULE_FLAG_CORE
880 };

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.30