2 * IRC - Internet Relay Chat, ircd/s_serv.c (formerly ircd/s_msg.c)
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #include "sprintf_irc.h"
46 #include "querycmds.h"
51 static int exit_new_server(aClient *cptr, aClient *sptr,
52 char *host, time_t timestamp, char *fmt, ...)
53 __attribute__ ((format(printf, 5, 6)));
57 #ifdef CRYPT_LINK_PASSWORD
59 /* This is not ANSI, but we have it anyway... */
60 char *crypt(const char *key, const char *salt);
62 #endif /* CRYPT_LINK_PASSWORD */
66 unsigned int max_connection_count = 0, max_client_count = 0;
68 static int exit_new_server(aClient *cptr, aClient *sptr,
69 char *host, time_t timestamp, char *fmt, ...)
73 (char *)RunMalloc(strlen(me.name) + strlen(host) + 22 + strlen(fmt));
76 return vexit_client_msg(cptr, cptr, &me, fmt, vl);
77 sprintf_irc(buf, ":%s SQUIT %s " TIME_T_FMT " :", me.name, host, timestamp);
79 vsendto_one(cptr, buf, vl);
85 static int a_kills_b_too(aClient *a, aClient *b)
87 for (; b != a && b != &me; b = b->serv->up);
88 return (a == b ? 1 : 0);
94 * parv[0] = sender prefix
95 * parv[1] = servername
97 * parv[3] = start timestamp
98 * parv[4] = link timestamp
99 * parv[5] = major protocol version: P09/P10
100 * parv[parc-1] = serverinfo
102 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
103 * numeric nick mask of this server.
104 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
106 int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
110 char info[REALLEN + 1], *inpath, *host, *s;
111 aClient *acptr, *bcptr, *LHcptr = NULL;
112 aConfItem *aconf = NULL, *bconf = NULL, *cconf, *lhconf = NULL;
113 int hop, ret, active_lh_line = 0;
114 unsigned short int prot;
115 time_t start_timestamp, timestamp = 0, recv_time, ghost = 0;
119 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
123 if (IsUserPort(cptr))
124 return exit_client_msg(cptr, cptr, &me,
125 "You cannot connect a server to a user port; connect to %s port %u",
128 recv_time = TStime();
130 inpath = get_client_name(cptr, TRUE);
133 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SERVER");
134 return exit_client(cptr, cptr, &me, "Need more parameters");
137 /* Detect protocol */
138 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
139 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
140 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
142 prot = atoi(parv[5] + 1);
143 if (prot > atoi(MAJOR_PROTOCOL))
144 prot = atoi(MAJOR_PROTOCOL);
145 /* Because the previous test is only in 2.10, the following is needed
146 * till all servers are 2.10: */
147 if (IsServer(cptr) && prot > Protocol(cptr))
148 prot = Protocol(cptr);
150 start_timestamp = atoi(parv[3]);
151 timestamp = atoi(parv[4]);
152 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
153 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
154 if ((timestamp < 780000000 || (hop == 1 && start_timestamp < 780000000)))
156 return exit_client_msg(cptr, sptr, &me,
157 "Bogus timestamps (%s %s)", parv[3], parv[4]);
159 strncpy(info, parv[parc - 1], REALLEN);
161 if (prot < atoi(MINOR_PROTOCOL))
163 sendto_ops("Got incompatible protocol version (%s) from %s",
164 parv[5], get_client_name(cptr, TRUE));
165 return exit_new_server(cptr, sptr, host, timestamp,
166 "Incompatible protocol: %s", parv[5]);
169 * Check for "FRENCH " infection ;-) (actually this should
170 * be replaced with routine to check the hostname syntax in
171 * general). [ This check is still needed, even after the parse
172 * is fixed, because someone can send "SERVER :foo bar " ].
173 * Also, changed to check other "difficult" characters, now
174 * that parse lets all through... --msa
176 if (strlen(host) > HOSTLEN)
177 host[HOSTLEN] = '\0';
178 for (ch = host; *ch; ch++)
179 if (*ch <= ' ' || *ch > '~')
181 if (*ch || !strchr(host, '.'))
183 sendto_ops("Bogus server name (%s) from %s",
184 host, get_client_name(cptr, TRUE));
185 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
191 * A local server introduces a new server behind this link.
192 * Check if this is allowed according L:, H: and Q: lines.
195 return exit_client_msg(cptr, cptr, &me,
196 "No server info specified for %s", host);
199 * See if the newly found server is behind a guaranteed
200 * leaf (L-line). If so, close the link.
202 if ((lhconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
203 (!lhconf->port || (hop > lhconf->port)))
206 * L: lines normally come in pairs, here we try to
207 * make sure that the oldest link is squitted, not
211 if (timestamp <= cptr->serv->timestamp)
212 LHcptr = NULL; /* Kill incoming server */
214 LHcptr = cptr; /* Squit ourselfs */
216 else if (!(lhconf = find_conf_host(cptr->confs, host, CONF_HUB)) ||
217 (lhconf->port && (hop > lhconf->port)))
221 /* Look for net junction causing this: */
222 LHcptr = NULL; /* incoming server */
224 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
225 if (IsJunction(ac3ptr))
233 if (IsUnknown(cptr) || IsHandshake(cptr))
238 * A local link that is still in undefined state wants
239 * to be a SERVER. Check if this is allowed and change
240 * status accordingly...
243 * If there is more then one server on the same machine
244 * that we try to connect to, it could be that the /CONNECT
245 * <mask> caused this connect to be put at the wrong place
246 * in the hashtable. --Run
247 * Same thing for Unknown connections that first send NICK.
249 * Better check if the two strings are (caseless) identical
250 * and not mess with hash internals.
253 if ((!(BadPtr(cptr->name)))
254 && (IsUnknown(cptr) || IsHandshake(cptr))
255 && strCasediff(cptr->name, host))
256 hChangeClient(cptr, host);
257 strncpy(cptr->name, host, sizeof(cptr->name) - 1);
258 strncpy(cptr->info, info[0] ? info : me.name, sizeof(cptr->info) - 1);
259 cptr->hopcount = hop;
261 /* check connection rules */
262 for (cconf = conf; cconf; cconf = cconf->next)
263 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0))
264 if (crule_eval(cconf->passwd))
267 sendto_ops("Refused connection from %s.", get_client_host(cptr));
268 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
271 if (check_server(cptr))
274 sendto_ops("Received unauthorized connection from %s.",
275 get_client_host(cptr));
276 return exit_client(cptr, cptr, &me, "No C/N conf lines");
283 if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
287 sendto_ops("Access denied. No N line for server %s", inpath);
288 return exit_client_msg(cptr, cptr, &me,
289 "Access denied. No N line for server %s", inpath);
291 sendto_ops("General C/N: line active: No N line for server %s", inpath);
293 find_conf(cptr->confs, "general.undernet.org", CONF_NOCONNECT_SERVER);
295 find_conf(cptr->confs, "general.undernet.org", CONF_CONNECT_SERVER);
296 if (!aconf || !bconf)
298 sendto_ops("Neither C/N lines for server %s nor "
299 "\"general.undernet.org\"", inpath);
300 return exit_client_msg(cptr, cptr, &me,
301 "No C/N lines for server %s", inpath);
305 else if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER)))
308 sendto_ops("Only N (no C) field for server %s", inpath);
309 return exit_client_msg(cptr, cptr, &me,
310 "Only N (no C) field for server %s", inpath);
313 #ifdef CRYPT_LINK_PASSWORD
314 /* passwd may be NULL. Head it off at the pass... */
319 salt[0] = aconf->passwd[0];
320 salt[1] = aconf->passwd[1];
322 encr = crypt(cptr->passwd, salt);
328 #endif /* CRYPT_LINK_PASSWORD */
330 if (*aconf->passwd && !!strcmp(aconf->passwd, encr))
333 sendto_ops("Access denied (passwd mismatch) %s", inpath);
334 return exit_client_msg(cptr, cptr, &me,
335 "No Access (passwd mismatch) %s", inpath);
337 #endif /* not GODMODE */
338 memset(cptr->passwd, 0, sizeof(cptr->passwd));
341 for (i = 0; i <= highest_fd; i++)
342 if (loc_clients[i] && IsServer(loc_clients[i]))
349 if (!IsUnknown(cptr))
351 s = strchr(aconf->host, '@');
352 *s = '\0'; /* should never be NULL */
353 Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]",
354 aconf->host, cptr->username));
355 if (match(aconf->host, cptr->username))
359 sendto_ops("Username mismatch [%s]v[%s] : %s",
360 aconf->host, cptr->username, get_client_name(cptr, TRUE));
361 return exit_client(cptr, cptr, &me, "Bad Username");
368 * We want to find IsConnecting() and IsHandshake() too,
370 * The second finds collisions with numeric representation of existing
371 * servers - these shouldn't happen anymore when all upgraded to 2.10.
374 while ((acptr = FindClient(host)) ||
375 (parc > 7 && (acptr = FindNServer(parv[6]))))
378 * This link is trying feed me a server that I already have
379 * access through another path
381 * Do not allow Uworld to do this.
382 * Do not allow servers that are juped.
383 * Do not allow servers that have older link timestamps
385 * Do not allow servers that use the same numeric as an existing
386 * server, but have a different name.
388 * If my ircd.conf sucks, I can try to connect to myself:
391 return exit_client_msg(cptr, cptr, &me,
392 "nick collision with me (%s)", host);
394 * Detect wrong numeric.
396 if (strCasediff(acptr->name, host))
398 sendto_serv_butone(cptr,
399 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
400 me.name, acptr->name, host);
401 return exit_client_msg(cptr, cptr, &me,
402 "NUMERIC collision between %s and %s."
403 " Is your server numeric correct ?", host, acptr->name);
406 * Kill our try, if we had one.
408 if (IsConnecting(acptr))
410 if (!active_lh_line && exit_client(cptr, acptr, &me,
411 "Just connected via another link") == CPTR_KILLED)
414 * We can have only ONE 'IsConnecting', 'IsHandshake' or
415 * 'IsServer', because new 'IsConnecting's are refused to
416 * the same server if we already had it.
421 * Avoid other nick collisions...
422 * This is a doubtfull test though, what else would it be
423 * when it has a server.name ?
425 else if (!IsServer(acptr) && !IsHandshake(acptr))
426 return exit_client_msg(cptr, cptr, &me,
427 "Nickname %s already exists!", host);
429 * Our new server might be a juped server,
430 * or someone trying abuse a second Uworld:
432 else if (IsServer(acptr) && (strnCasecmp(acptr->info, "JUPE", 4) == 0 ||
433 find_conf_host(cptr->confs, acptr->name, CONF_UWORLD)))
436 return exit_client(cptr, sptr, &me, acptr->info);
437 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
438 me.name, parv[0], parv[1], cptr->name);
439 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
442 * Of course we find the handshake this link was before :)
444 else if (IsHandshake(acptr) && acptr == cptr)
447 * Here we have a server nick collision...
448 * We don't want to kill the link that was last /connected,
449 * but we neither want to kill a good (old) link.
450 * Therefor we kill the second youngest link.
454 aClient *c2ptr = NULL, *c3ptr = acptr;
455 aClient *ac2ptr, *ac3ptr;
457 /* Search youngest link: */
458 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
459 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
463 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
464 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
467 if (timestamp > c3ptr->serv->timestamp)
470 c2ptr = acptr; /* Make sure they differ */
472 /* Search second youngest link: */
473 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
474 if (ac2ptr != c3ptr &&
475 ac2ptr->serv->timestamp >
476 (c2ptr ? c2ptr->serv->timestamp : timestamp))
480 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
481 if (ac2ptr != c3ptr &&
482 ac2ptr->serv->timestamp >
483 (c2ptr ? c2ptr->serv->timestamp : timestamp))
486 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
488 /* If timestamps are equal, decide which link to break
491 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
492 (c3ptr ? c3ptr->serv->timestamp : timestamp))
499 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
504 n2up = IsServer(sptr) ? sptr->name : me.name;
509 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
514 n3up = IsServer(sptr) ? sptr->name : me.name;
516 if (strcmp(n2, n2up) > 0)
518 if (strcmp(n3, n3up) > 0)
520 if (strcmp(n3, n2) > 0)
527 /* Now squit the second youngest link: */
529 return exit_new_server(cptr, sptr, host, timestamp,
530 "server %s already exists and is %ld seconds younger.",
531 host, (long)acptr->serv->timestamp - (long)timestamp);
532 else if (c2ptr->from == cptr || IsServer(sptr))
534 aClient *killedptrfrom = c2ptr->from;
538 * If the L: or H: line also gets rid of this link,
539 * we sent just one squit.
541 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
544 * If breaking the loop here solves the L: or H:
545 * line problem, we don't squit that.
547 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
552 * If we still have a L: or H: line problem,
553 * we prefer to squit the new server, solving
554 * loop and L:/H: line problem with only one squit.
561 * If the new server was introduced by a server that caused a
562 * Ghost less then 20 seconds ago, this is probably also
563 * a Ghost... (20 seconds is more then enough because all
564 * SERVER messages are at the beginning of a net.burst). --Run
566 if (now - cptr->serv->ghost < 20)
568 killedptrfrom = acptr->from;
569 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
572 else if (exit_client_msg(cptr, c2ptr, &me,
573 "Loop <-- %s (new link is %ld seconds younger)", host,
574 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
575 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
578 * Did we kill the incoming server off already ?
580 if (killedptrfrom == cptr)
587 if (LHcptr && a_kills_b_too(LHcptr, acptr))
589 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
598 * We can't believe it is a lagged server message
599 * when it directly connects to us...
600 * kill the older link at the ghost, rather then
601 * at the second youngest link, assuming it isn't
604 ghost = now; /* Mark that it caused a ghost */
605 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
615 return exit_new_server(cptr, sptr, host, timestamp,
616 (active_lh_line == 2) ?
617 "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
618 get_client_name(cptr, TRUE), host,
619 lhconf ? (lhconf->host ? lhconf->host : "*") : "!");
622 register int killed = a_kills_b_too(LHcptr, sptr);
623 if (active_lh_line < 3)
625 if (exit_client_msg(cptr, LHcptr, &me,
626 (active_lh_line == 2) ?
627 "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
628 get_client_name(cptr, TRUE), host,
629 lhconf ? (lhconf->host ? lhconf->host : "*") : "!") == CPTR_KILLED)
635 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
639 * Did we kill the incoming server off already ?
649 * Server is informing about a new server behind
650 * this link. Create REMOTE server structure,
651 * add it to list and propagate word to my other
655 acptr = make_client(cptr, STAT_SERVER);
657 acptr->serv->prot = prot;
658 acptr->serv->timestamp = timestamp;
659 acptr->hopcount = hop;
660 strncpy(acptr->name, host, sizeof(acptr->name) - 1);
661 strncpy(acptr->info, info, sizeof(acptr->info) - 1);
662 acptr->serv->up = sptr;
663 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
664 /* Use cptr, because we do protocol 9 -> 10 translation
665 for numeric nicks ! */
666 SetServerYXX(cptr, acptr, parv[6]);
667 Count_newremoteserver(nrof);
668 if (Protocol(acptr) < 10)
669 acptr->flags |= FLAGS_TS8;
670 add_client_to_list(acptr);
674 if (Protocol(acptr) > 9)
676 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
677 sptr->name, acptr->name);
681 * Old sendto_serv_but_one() call removed because we now need to send
682 * different names to different servers (domain name matching).
684 for (i = 0; i <= highest_fd; i++)
686 if (!(bcptr = loc_clients[i]) || !IsServer(bcptr) ||
687 bcptr == cptr || IsMe(bcptr))
689 if (!(cconf = bcptr->serv->nline))
691 sendto_ops("Lost N-line for %s on %s. Closing",
692 get_client_name(cptr, TRUE), host);
693 return exit_client(cptr, cptr, &me, "Lost N line");
695 if (match(my_name_for_link(me.name, cconf), acptr->name) == 0)
697 if (Protocol(bcptr) > 9)
698 sendto_one(bcptr, "%s SERVER %s %d 0 %s %s %s%s 0 :%s",
699 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
700 NumServCap(acptr), acptr->info);
702 sendto_one(bcptr, ":%s SERVER %s %d 0 %s %s %s%s 0 :%s",
703 parv[0], acptr->name, hop + 1, parv[4], parv[5],
704 NumServCap(acptr), acptr->info);
709 if (IsUnknown(cptr) || IsHandshake(cptr))
712 cptr->serv->timestamp = timestamp;
713 cptr->serv->prot = prot;
714 cptr->serv->ghost = ghost;
715 SetServerYXX(cptr, cptr, parv[6]);
716 if (start_timestamp > 780000000)
718 #ifndef RELIABLE_CLOCK
720 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
721 TIME_T_FMT, me.serv->timestamp, start_timestamp);
722 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
723 TIME_T_FMT " ; difference %ld",
724 recv_time, timestamp, timestamp - recv_time);
726 if (start_timestamp < me.serv->timestamp)
728 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
729 start_timestamp, me.serv->timestamp);
730 me.serv->timestamp = start_timestamp;
731 TSoffset += timestamp - recv_time;
732 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
734 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
735 cptr->serv->timestamp = TStime();
737 else if (timestamp != recv_time)
738 /* Equal start times, we have a collision. Let the connected-to server
739 decide. This assumes leafs issue more than half of the connection
743 cptr->serv->timestamp = TStime();
744 else if (IsHandshake(cptr))
746 sendto_ops("clock adjusted by adding %d",
747 (int)(timestamp - recv_time));
748 TSoffset += timestamp - recv_time;
751 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
752 if (start_timestamp < me.serv->timestamp)
753 me.serv->timestamp = start_timestamp;
755 cptr->serv->timestamp = TStime();
759 ret = m_server_estab(cptr, aconf, bconf);
763 #ifdef RELIABLE_CLOCK
764 if (abs(cptr->serv->timestamp - recv_time) > 30)
766 sendto_ops("Connected to a net with a timestamp-clock"
767 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
768 " this.", timestamp - recv_time);
769 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
770 me.name, TStime(), me.name);
780 * May only be called after a SERVER was received from cptr,
781 * and thus make_server was called, and serv->prot set. --Run
783 int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf)
789 split = (strCasediff(cptr->name, cptr->sockhost)
790 && strnCasecmp(cptr->info, "JUPE", 4));
791 inpath = get_client_name(cptr, TRUE);
796 if (bconf->passwd[0])
797 sendto_one(cptr, "PASS :%s", bconf->passwd);
799 * Pass my info to the new server
801 sendto_one(cptr, "SERVER %s 1 " TIME_T_FMT " " TIME_T_FMT " J%s %s%s :%s",
802 my_name_for_link(me.name, aconf), me.serv->timestamp,
803 cptr->serv->timestamp, MAJOR_PROTOCOL, NumServCap(&me),
804 (me.info[0]) ? (me.info) : "IRCers United");
806 IPcheck_connect_fail(cptr); /* Don't charge this IP# for connecting */
809 det_confs_butmask(cptr,
810 CONF_LEAF | CONF_HUB | CONF_NOCONNECT_SERVER | CONF_UWORLD);
812 if (!IsHandshake(cptr))
815 Count_unknownbecomesserver(nrof);
816 if (Protocol(cptr) > 9)
819 cptr->flags |= FLAGS_TS8;
821 if (cptr->serv->user && *cptr->serv->by &&
822 (acptr = findNUser(cptr->serv->by)) && acptr->user == cptr->serv->user)
824 if (MyUser(acptr) || Protocol(acptr->from) < 10)
825 sendto_one(acptr, ":%s NOTICE %s :Link with %s established.",
826 me.name, acptr->name, inpath);
828 sendto_one(acptr, "%s NOTICE %s%s :Link with %s established.",
829 NumServ(&me), NumNick(acptr), inpath);
833 sendto_lops_butone(acptr, "Link with %s established.", inpath);
834 cptr->serv->up = &me;
835 cptr->serv->updown = add_dlink(&me.serv->down, cptr);
836 cptr->serv->nline = aconf;
837 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", me.name, cptr->name);
840 * Old sendto_serv_but_one() call removed because we now
841 * need to send different names to different servers
842 * (domain name matching) Send new server to other servers.
844 for (i = 0; i <= highest_fd; i++)
846 if (!(acptr = loc_clients[i]) || !IsServer(acptr) ||
847 acptr == cptr || IsMe(acptr))
849 if ((aconf = acptr->serv->nline) &&
850 !match(my_name_for_link(me.name, aconf), cptr->name))
854 if (Protocol(acptr) > 9)
856 "%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :[%s] %s",
857 NumServ(&me), cptr->name, cptr->serv->timestamp,
858 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr), NumServCap(cptr),
859 cptr->sockhost, cptr->info);
862 ":%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :[%s] %s", me.name,
863 cptr->name, cptr->serv->timestamp,
864 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr), NumServCap(cptr),
865 cptr->sockhost, cptr->info);
869 if (Protocol(acptr) > 9)
870 sendto_one(acptr, "%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
871 NumServ(&me), cptr->name, cptr->serv->timestamp,
872 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
873 NumServCap(cptr), cptr->info);
875 sendto_one(acptr, ":%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
876 me.name, cptr->name, cptr->serv->timestamp,
877 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
878 NumServCap(cptr), cptr->info);
883 * Pass on my client information to the new server
885 * First, pass only servers (idea is that if the link gets
886 * cancelled beacause the server was already there,
887 * there are no NICK's to be cancelled...). Of course,
888 * if cancellation occurs, all this info is sent anyway,
889 * and I guess the link dies when a read is attempted...? --msa
891 * Note: Link cancellation to occur at this point means
892 * that at least two servers from my fragment are building
893 * up connection this other fragment at the same time, it's
894 * a race condition, not the normal way of operation...
897 aconf = cptr->serv->nline;
898 for (acptr = &me; acptr; acptr = acptr->prev)
900 /* acptr->from == acptr for acptr == cptr */
901 if (acptr->from == cptr)
906 (Protocol(acptr) > 9) ? (IsBurst(acptr) ? "J" : "P") : "P0";
907 if (match(my_name_for_link(me.name, aconf), acptr->name) == 0)
909 split = (MyConnect(acptr) && strCasediff(acptr->name, acptr->sockhost) &&
910 strnCasecmp(acptr->info, "JUPE", 4));
913 if (Protocol(cptr) > 9)
915 "%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :[%s] %s",
916 NumServ(acptr->serv->up), acptr->name,
917 acptr->hopcount + 1, acptr->serv->timestamp,
918 protocol_str, Protocol(acptr),
919 NumServCap(acptr), acptr->sockhost, acptr->info);
922 ":%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :[%s] %s",
923 acptr->serv->up->name, acptr->name,
924 acptr->hopcount + 1, acptr->serv->timestamp,
925 protocol_str, Protocol(acptr),
926 NumServCap(acptr), acptr->sockhost, acptr->info);
930 if (Protocol(cptr) > 9)
932 "%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
933 NumServ(acptr->serv->up), acptr->name,
934 acptr->hopcount + 1, acptr->serv->timestamp,
935 protocol_str, Protocol(acptr), NumServCap(acptr), acptr->info);
938 ":%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
939 acptr->serv->up->name, acptr->name,
940 acptr->hopcount + 1, acptr->serv->timestamp,
941 protocol_str, Protocol(acptr), NumServCap(acptr), acptr->info);
946 for (acptr = &me; acptr; acptr = acptr->prev)
948 /* acptr->from == acptr for acptr == cptr */
949 if (acptr->from == cptr)
953 if (Protocol(cptr) < 10)
956 * IsUser(x) is true only *BOTH* NICK and USER have
957 * been received. -avalon
958 * Or only NICK in new format. --Run
960 sendto_one(cptr, ":%s NICK %s %d " TIME_T_FMT " %s %s %s :%s",
961 acptr->user->server->name,
962 acptr->name, acptr->hopcount + 1, acptr->lastnick,
963 acptr->user->username, acptr->user->host,
964 acptr->user->server->name, acptr->info);
965 send_umode(cptr, acptr, 0, SEND_UMODES);
966 send_user_joins(cptr, acptr);
971 char *s = umode_str(acptr);
972 sendto_one(cptr, *s ?
973 "%s NICK %s %d " TIME_T_FMT " %s %s +%s %s %s%s :%s" :
974 "%s NICK %s %d " TIME_T_FMT " %s %s %s%s %s%s :%s",
975 NumServ(acptr->user->server),
976 acptr->name, acptr->hopcount + 1, acptr->lastnick,
977 acptr->user->username, acptr->user->host,
978 s, inttobase64(xxx_buf, ntohl(acptr->ip.s_addr), 6),
979 NumNick(acptr), acptr->info);
984 * Last, send the BURST.
985 * (Or for 2.9 servers: pass all channels plus statuses)
988 Reg1 aChannel *chptr;
989 for (chptr = channel; chptr; chptr = chptr->nextch)
990 send_channel_modes(cptr, chptr);
992 if (Protocol(cptr) >= 10)
993 sendto_one(cptr, "%s END_OF_BURST", NumServ(&me));
1000 * parv[0] = sender prefix
1001 * parv[parc-1] = text
1003 int m_error(aClient *cptr, aClient *sptr, int parc, char *parv[])
1007 para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
1009 Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", sptr->name, para));
1011 * Ignore error messages generated by normal user clients
1012 * (because ill-behaving user clients would flood opers
1013 * screen otherwise). Pass ERROR's from other sources to
1014 * the local operator...
1018 if (IsUnknown(cptr))
1019 return exit_client_msg(cptr, cptr, &me, "Register first");
1022 sendto_ops("ERROR :from %s -- %s", get_client_name(cptr, FALSE), para);
1024 sendto_ops("ERROR :from %s via %s -- %s",
1025 sptr->name, get_client_name(cptr, FALSE), para);
1029 RunFree(sptr->serv->last_error_msg);
1030 DupString(sptr->serv->last_error_msg, para);
1037 * m_end_of_burst - Added Xorath 6-14-96, rewritten by Run 24-7-96
1038 * - and fixed by record and Kev 8/1/96
1039 * - and really fixed by Run 15/8/96 :p
1040 * This the last message in a net.burst.
1041 * It clears a flag for the server sending the burst.
1043 * parv[0] - sender prefix
1045 int m_end_of_burst(aClient *cptr, aClient *sptr, int UNUSED(parc),
1046 char **UNUSED(parv))
1048 if (!IsServer(sptr))
1051 sendto_op_mask(SNO_NETWORK, "Completed net.burst from %s.", sptr->name);
1053 sendto_serv_butone(cptr, "%s END_OF_BURST", NumServ(sptr));
1055 sendto_highprot_butone(cptr, 10, "%s END_OF_BURST", NumServ(sptr));
1059 if (MyConnect(sptr))
1060 sendto_one(sptr, "%s EOB_ACK", NumServ(&me));
1066 * m_end_of_burst_ack
1068 * This the acknowledge message of the `END_OF_BURST' message.
1069 * It clears a flag for the server receiving the burst.
1071 * parv[0] - sender prefix
1073 int m_end_of_burst_ack(aClient *cptr, aClient *sptr, int UNUSED(parc),
1074 char **UNUSED(parv))
1076 if (!IsServer(sptr))
1079 sendto_op_mask(SNO_NETWORK, "%s acknowledged end of net.burst.", sptr->name);
1081 sendto_serv_butone(cptr, "%s EOB_ACK", NumServ(sptr));
1083 sendto_highprot_butone(cptr, 10, "%s EOB_ACK", NumServ(sptr));
1085 ClearBurstAck(sptr);
1093 * Writes to all +g users; for sending wall type debugging/anti-hack info.
1094 * Added 23 Apr 1998 --Run
1096 * parv[0] - sender prefix
1097 * parv[parc-1] - message text
1099 int m_desynch(aClient *cptr, aClient *sptr, int parc, char *parv[])
1101 if (IsServer(sptr) && parc >= 2)
1105 /* Send message to local +g clients as if it were a wallops */
1106 sprintf_irc(sendbuf, ":%s WALLOPS :%s", parv[0], parv[parc - 1]);
1107 for (i = 0; i <= highest_fd; i++)
1108 if ((acptr = loc_clients[i]) && !IsServer(acptr) && !IsMe(acptr) &&
1110 sendbufto_one(acptr);
1111 /* Send message to remote +g clients */
1112 sendto_g_serv_butone(cptr, "%s DESYNCH :%s", NumServ(sptr), parv[parc - 1]);