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);
91 extern unsigned short server_port;
96 * parv[0] = sender prefix
97 * parv[1] = servername
99 * parv[3] = start timestamp
100 * parv[4] = link timestamp
101 * parv[5] = major protocol version: P09/P10
102 * parv[parc-1] = serverinfo
104 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
105 * numeric nick mask of this server.
106 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
108 int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
112 char info[REALLEN + 1], *inpath, *host, *s;
113 aClient *acptr, *bcptr, *LHcptr = NULL;
114 aConfItem *aconf = NULL, *bconf = NULL, *cconf, *lhconf = NULL;
115 int hop, ret, active_lh_line = 0;
116 unsigned short int prot;
117 time_t start_timestamp, timestamp = 0, recv_time, ghost = 0;
121 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
125 if (IsUserPort(cptr))
126 return exit_client_msg(cptr, cptr, &me,
127 "You cannot connect a server to a user port; connect to %s port %u",
128 me.name, server_port);
130 recv_time = TStime();
132 inpath = get_client_name(cptr, TRUE);
135 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SERVER");
136 return exit_client(cptr, cptr, &me, "Need more parameters");
139 /* Detect protocol */
140 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
141 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
142 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
144 prot = atoi(parv[5] + 1);
145 if (prot > atoi(MAJOR_PROTOCOL))
146 prot = atoi(MAJOR_PROTOCOL);
147 /* Because the previous test is only in 2.10, the following is needed
148 * till all servers are 2.10: */
149 if (IsServer(cptr) && prot > Protocol(cptr))
150 prot = Protocol(cptr);
152 start_timestamp = atoi(parv[3]);
153 timestamp = atoi(parv[4]);
154 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
155 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
156 if ((timestamp < 780000000 || (hop == 1 && start_timestamp < 780000000)))
158 return exit_client_msg(cptr, sptr, &me,
159 "Bogus timestamps (%s %s)", parv[3], parv[4]);
161 strncpy(info, parv[parc - 1], REALLEN);
163 if (prot < atoi(MINOR_PROTOCOL))
165 sendto_ops("Got incompatible protocol version (%s) from %s",
166 parv[5], get_client_name(cptr, TRUE));
167 return exit_new_server(cptr, sptr, host, timestamp,
168 "Incompatible protocol: %s", parv[5]);
171 * Check for "FRENCH " infection ;-) (actually this should
172 * be replaced with routine to check the hostname syntax in
173 * general). [ This check is still needed, even after the parse
174 * is fixed, because someone can send "SERVER :foo bar " ].
175 * Also, changed to check other "difficult" characters, now
176 * that parse lets all through... --msa
178 if (strlen(host) > HOSTLEN)
179 host[HOSTLEN] = '\0';
180 for (ch = host; *ch; ch++)
181 if (*ch <= ' ' || *ch > '~')
183 if (*ch || !strchr(host, '.'))
185 sendto_ops("Bogus server name (%s) from %s",
186 host, get_client_name(cptr, TRUE));
187 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
193 * A local server introduces a new server behind this link.
194 * Check if this is allowed according L:, H: and Q: lines.
197 return exit_client_msg(cptr, cptr, &me,
198 "No server info specified for %s", host);
201 * See if the newly found server is behind a guaranteed
202 * leaf (L-line). If so, close the link.
204 if ((lhconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
205 (!lhconf->port || (hop > lhconf->port)))
208 * L: lines normally come in pairs, here we try to
209 * make sure that the oldest link is squitted, not
213 if (timestamp <= cptr->serv->timestamp)
214 LHcptr = NULL; /* Kill incoming server */
216 LHcptr = cptr; /* Squit ourselfs */
218 else if (!(lhconf = find_conf_host(cptr->confs, host, CONF_HUB)) ||
219 (lhconf->port && (hop > lhconf->port)))
223 /* Look for net junction causing this: */
224 LHcptr = NULL; /* incoming server */
226 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
227 if (IsJunction(ac3ptr))
235 if (IsUnknown(cptr) || IsHandshake(cptr))
240 * A local link that is still in undefined state wants
241 * to be a SERVER. Check if this is allowed and change
242 * status accordingly...
245 * If there is more then one server on the same machine
246 * that we try to connect to, it could be that the /CONNECT
247 * <mask> caused this connect to be put at the wrong place
248 * in the hashtable. --Run
249 * Same thing for Unknown connections that first send NICK.
251 * Better check if the two strings are (caseless) identical
252 * and not mess with hash internals.
255 if ((!(BadPtr(cptr->name)))
256 && (IsUnknown(cptr) || IsHandshake(cptr))
257 && strCasediff(cptr->name, host))
258 hChangeClient(cptr, host);
259 strncpy(cptr->name, host, sizeof(cptr->name) - 1);
260 strncpy(cptr->info, info[0] ? info : me.name, sizeof(cptr->info) - 1);
261 cptr->hopcount = hop;
263 /* check connection rules */
264 for (cconf = conf; cconf; cconf = cconf->next)
265 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0))
266 if (crule_eval(cconf->passwd))
269 sendto_ops("Refused connection from %s.", get_client_host(cptr));
270 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
273 if (check_server(cptr))
276 sendto_ops("Received unauthorized connection from %s.",
277 get_client_host(cptr));
278 return exit_client(cptr, cptr, &me, "No C/N conf lines");
285 if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
289 sendto_ops("Access denied. No N line for server %s", inpath);
290 return exit_client_msg(cptr, cptr, &me,
291 "Access denied. No N line for server %s", inpath);
293 sendto_ops("General C/N: line active: No N line for server %s", inpath);
295 find_conf(cptr->confs, "general.undernet.org", CONF_NOCONNECT_SERVER);
297 find_conf(cptr->confs, "general.undernet.org", CONF_CONNECT_SERVER);
298 if (!aconf || !bconf)
300 sendto_ops("Neither C/N lines for server %s nor "
301 "\"general.undernet.org\"", inpath);
302 return exit_client_msg(cptr, cptr, &me,
303 "No C/N lines for server %s", inpath);
307 else if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER)))
310 sendto_ops("Only N (no C) field for server %s", inpath);
311 return exit_client_msg(cptr, cptr, &me,
312 "Only N (no C) field for server %s", inpath);
315 #ifdef CRYPT_LINK_PASSWORD
316 /* passwd may be NULL. Head it off at the pass... */
321 salt[0] = aconf->passwd[0];
322 salt[1] = aconf->passwd[1];
324 encr = crypt(cptr->passwd, salt);
330 #endif /* CRYPT_LINK_PASSWORD */
332 if (*aconf->passwd && !!strcmp(aconf->passwd, encr))
335 sendto_ops("Access denied (passwd mismatch) %s", inpath);
336 return exit_client_msg(cptr, cptr, &me,
337 "No Access (passwd mismatch) %s", inpath);
339 #endif /* not GODMODE */
340 memset(cptr->passwd, 0, sizeof(cptr->passwd));
343 for (i = 0; i <= highest_fd; i++)
344 if (loc_clients[i] && IsServer(loc_clients[i]))
351 if (!IsUnknown(cptr))
353 s = strchr(aconf->host, '@');
354 *s = '\0'; /* should never be NULL */
355 Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]",
356 aconf->host, cptr->username));
357 if (match(aconf->host, cptr->username))
361 sendto_ops("Username mismatch [%s]v[%s] : %s",
362 aconf->host, cptr->username, get_client_name(cptr, TRUE));
363 return exit_client(cptr, cptr, &me, "Bad Username");
370 * We want to find IsConnecting() and IsHandshake() too,
372 * The second finds collisions with numeric representation of existing
373 * servers - these shouldn't happen anymore when all upgraded to 2.10.
376 while ((acptr = FindClient(host)) ||
377 (parc > 7 && (acptr = FindNServer(parv[6]))))
380 * This link is trying feed me a server that I already have
381 * access through another path
383 * Do not allow Uworld to do this.
384 * Do not allow servers that are juped.
385 * Do not allow servers that have older link timestamps
387 * Do not allow servers that use the same numeric as an existing
388 * server, but have a different name.
390 * If my ircd.conf sucks, I can try to connect to myself:
393 return exit_client_msg(cptr, cptr, &me,
394 "nick collision with me (%s)", host);
396 * Detect wrong numeric.
398 if (strCasediff(acptr->name, host))
400 sendto_serv_butone(cptr,
401 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
402 me.name, acptr->name, host);
403 return exit_client_msg(cptr, cptr, &me,
404 "NUMERIC collision between %s and %s."
405 " Is your server numeric correct ?", host, acptr->name);
408 * Kill our try, if we had one.
410 if (IsConnecting(acptr))
412 if (!active_lh_line && exit_client(cptr, acptr, &me,
413 "Just connected via another link") == CPTR_KILLED)
416 * We can have only ONE 'IsConnecting', 'IsHandshake' or
417 * 'IsServer', because new 'IsConnecting's are refused to
418 * the same server if we already had it.
423 * Avoid other nick collisions...
424 * This is a doubtfull test though, what else would it be
425 * when it has a server.name ?
427 else if (!IsServer(acptr) && !IsHandshake(acptr))
428 return exit_client_msg(cptr, cptr, &me,
429 "Nickname %s already exists!", host);
431 * Our new server might be a juped server,
432 * or someone trying abuse a second Uworld:
434 else if (IsServer(acptr) && (strnCasecmp(acptr->info, "JUPE", 4) == 0 ||
435 find_conf_host(cptr->confs, acptr->name, CONF_UWORLD)))
438 return exit_client(cptr, sptr, &me, acptr->info);
439 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
440 me.name, parv[0], parv[1], cptr->name);
441 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
444 * Of course we find the handshake this link was before :)
446 else if (IsHandshake(acptr) && acptr == cptr)
449 * Here we have a server nick collision...
450 * We don't want to kill the link that was last /connected,
451 * but we neither want to kill a good (old) link.
452 * Therefor we kill the second youngest link.
456 aClient *c2ptr = NULL, *c3ptr = acptr;
457 aClient *ac2ptr, *ac3ptr;
459 /* Search youngest link: */
460 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
461 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
465 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
466 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
469 if (timestamp > c3ptr->serv->timestamp)
472 c2ptr = acptr; /* Make sure they differ */
474 /* Search second youngest link: */
475 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
476 if (ac2ptr != c3ptr &&
477 ac2ptr->serv->timestamp >
478 (c2ptr ? c2ptr->serv->timestamp : timestamp))
482 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
483 if (ac2ptr != c3ptr &&
484 ac2ptr->serv->timestamp >
485 (c2ptr ? c2ptr->serv->timestamp : timestamp))
488 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
490 /* If timestamps are equal, decide which link to break
493 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
494 (c3ptr ? c3ptr->serv->timestamp : timestamp))
501 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
506 n2up = IsServer(sptr) ? sptr->name : me.name;
511 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
516 n3up = IsServer(sptr) ? sptr->name : me.name;
518 if (strcmp(n2, n2up) > 0)
520 if (strcmp(n3, n3up) > 0)
522 if (strcmp(n3, n2) > 0)
529 /* Now squit the second youngest link: */
531 return exit_new_server(cptr, sptr, host, timestamp,
532 "server %s already exists and is %ld seconds younger.",
533 host, (long)acptr->serv->timestamp - (long)timestamp);
534 else if (c2ptr->from == cptr || IsServer(sptr))
536 aClient *killedptrfrom = c2ptr->from;
540 * If the L: or H: line also gets rid of this link,
541 * we sent just one squit.
543 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
546 * If breaking the loop here solves the L: or H:
547 * line problem, we don't squit that.
549 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
554 * If we still have a L: or H: line problem,
555 * we prefer to squit the new server, solving
556 * loop and L:/H: line problem with only one squit.
563 * If the new server was introduced by a server that caused a
564 * Ghost less then 20 seconds ago, this is probably also
565 * a Ghost... (20 seconds is more then enough because all
566 * SERVER messages are at the beginning of a net.burst). --Run
568 if (now - cptr->serv->ghost < 20)
570 killedptrfrom = acptr->from;
571 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
574 else if (exit_client_msg(cptr, c2ptr, &me,
575 "Loop <-- %s (new link is %ld seconds younger)", host,
576 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
577 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
580 * Did we kill the incoming server off already ?
582 if (killedptrfrom == cptr)
589 if (LHcptr && a_kills_b_too(LHcptr, acptr))
591 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
600 * We can't believe it is a lagged server message
601 * when it directly connects to us...
602 * kill the older link at the ghost, rather then
603 * at the second youngest link, assuming it isn't
606 ghost = now; /* Mark that it caused a ghost */
607 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
617 return exit_new_server(cptr, sptr, host, timestamp,
618 (active_lh_line == 2) ?
619 "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
620 get_client_name(cptr, TRUE), host,
621 lhconf ? (lhconf->host ? lhconf->host : "*") : "!");
624 register int killed = a_kills_b_too(LHcptr, sptr);
625 if (active_lh_line < 3)
627 if (exit_client_msg(cptr, LHcptr, &me,
628 (active_lh_line == 2) ?
629 "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
630 get_client_name(cptr, TRUE), host,
631 lhconf ? (lhconf->host ? lhconf->host : "*") : "!") == CPTR_KILLED)
637 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
641 * Did we kill the incoming server off already ?
651 * Server is informing about a new server behind
652 * this link. Create REMOTE server structure,
653 * add it to list and propagate word to my other
657 acptr = make_client(cptr, STAT_SERVER);
659 acptr->serv->prot = prot;
660 acptr->serv->timestamp = timestamp;
661 acptr->hopcount = hop;
662 strncpy(acptr->name, host, sizeof(acptr->name) - 1);
663 strncpy(acptr->info, info, sizeof(acptr->info) - 1);
664 acptr->serv->up = sptr;
665 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
666 /* Use cptr, because we do protocol 9 -> 10 translation
667 for numeric nicks ! */
668 SetServerYXX(cptr, acptr, parv[6]);
669 Count_newremoteserver(nrof);
670 if (Protocol(acptr) < 10)
671 acptr->flags |= FLAGS_TS8;
672 add_client_to_list(acptr);
676 if (Protocol(acptr) > 9)
678 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
679 sptr->name, acptr->name);
683 * Old sendto_serv_but_one() call removed because we now need to send
684 * different names to different servers (domain name matching).
686 for (i = 0; i <= highest_fd; i++)
688 if (!(bcptr = loc_clients[i]) || !IsServer(bcptr) ||
689 bcptr == cptr || IsMe(bcptr))
691 if (!(cconf = bcptr->serv->nline))
693 sendto_ops("Lost N-line for %s on %s. Closing",
694 get_client_name(cptr, TRUE), host);
695 return exit_client(cptr, cptr, &me, "Lost N line");
697 if (match(my_name_for_link(me.name, cconf), acptr->name) == 0)
699 if (Protocol(bcptr) > 9)
700 sendto_one(bcptr, "%s SERVER %s %d 0 %s %s %s%s 0 :%s",
701 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
702 NumServCap(acptr), acptr->info);
704 sendto_one(bcptr, ":%s SERVER %s %d 0 %s %s %s%s 0 :%s",
705 parv[0], acptr->name, hop + 1, parv[4], parv[5],
706 NumServCap(acptr), acptr->info);
711 if (IsUnknown(cptr) || IsHandshake(cptr))
714 cptr->serv->timestamp = timestamp;
715 cptr->serv->prot = prot;
716 cptr->serv->ghost = ghost;
717 SetServerYXX(cptr, cptr, parv[6]);
718 if (start_timestamp > 780000000)
720 #ifndef RELIABLE_CLOCK
722 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
723 TIME_T_FMT, me.serv->timestamp, start_timestamp);
724 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
725 TIME_T_FMT " ; difference %ld",
726 recv_time, timestamp, timestamp - recv_time);
728 if (start_timestamp < me.serv->timestamp)
730 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
731 start_timestamp, me.serv->timestamp);
732 me.serv->timestamp = start_timestamp;
733 TSoffset += timestamp - recv_time;
734 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
736 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
737 cptr->serv->timestamp = TStime();
739 else if (timestamp != recv_time)
740 /* Equal start times, we have a collision. Let the connected-to server
741 decide. This assumes leafs issue more than half of the connection
745 cptr->serv->timestamp = TStime();
746 else if (IsHandshake(cptr))
748 sendto_ops("clock adjusted by adding %d",
749 (int)(timestamp - recv_time));
750 TSoffset += timestamp - recv_time;
753 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
754 if (start_timestamp < me.serv->timestamp)
755 me.serv->timestamp = start_timestamp;
757 cptr->serv->timestamp = TStime();
761 ret = m_server_estab(cptr, aconf, bconf);
765 #ifdef RELIABLE_CLOCK
766 if (abs(cptr->serv->timestamp - recv_time) > 30)
768 sendto_ops("Connected to a net with a timestamp-clock"
769 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
770 " this.", timestamp - recv_time);
771 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
772 me.name, TStime(), me.name);
782 * May only be called after a SERVER was received from cptr,
783 * and thus make_server was called, and serv->prot set. --Run
785 int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf)
791 split = (strCasediff(cptr->name, cptr->sockhost)
792 && strnCasecmp(cptr->info, "JUPE", 4));
793 inpath = get_client_name(cptr, TRUE);
798 if (bconf->passwd[0])
799 sendto_one(cptr, "PASS :%s", bconf->passwd);
801 * Pass my info to the new server
803 sendto_one(cptr, "SERVER %s 1 " TIME_T_FMT " " TIME_T_FMT " J%s %s%s :%s",
804 my_name_for_link(me.name, aconf), me.serv->timestamp,
805 cptr->serv->timestamp, MAJOR_PROTOCOL, NumServCap(&me),
806 (me.info[0]) ? (me.info) : "IRCers United");
808 IPcheck_connect_fail(cptr); /* Don't charge this IP# for connecting */
811 det_confs_butmask(cptr,
812 CONF_LEAF | CONF_HUB | CONF_NOCONNECT_SERVER | CONF_UWORLD);
814 if (!IsHandshake(cptr))
817 Count_unknownbecomesserver(nrof);
818 if (Protocol(cptr) > 9)
821 cptr->flags |= FLAGS_TS8;
823 if (cptr->serv->user && *cptr->serv->by &&
824 (acptr = findNUser(cptr->serv->by)) && acptr->user == cptr->serv->user)
826 if (MyUser(acptr) || Protocol(acptr->from) < 10)
827 sendto_one(acptr, ":%s NOTICE %s :Link with %s established.",
828 me.name, acptr->name, inpath);
830 sendto_one(acptr, "%s NOTICE %s%s :Link with %s established.",
831 NumServ(&me), NumNick(acptr), inpath);
835 sendto_lops_butone(acptr, "Link with %s established.", inpath);
836 cptr->serv->up = &me;
837 cptr->serv->updown = add_dlink(&me.serv->down, cptr);
838 cptr->serv->nline = aconf;
839 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", me.name, cptr->name);
842 * Old sendto_serv_but_one() call removed because we now
843 * need to send different names to different servers
844 * (domain name matching) Send new server to other servers.
846 for (i = 0; i <= highest_fd; i++)
848 if (!(acptr = loc_clients[i]) || !IsServer(acptr) ||
849 acptr == cptr || IsMe(acptr))
851 if ((aconf = acptr->serv->nline) &&
852 !match(my_name_for_link(me.name, aconf), cptr->name))
856 if (Protocol(acptr) > 9)
858 "%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :[%s] %s",
859 NumServ(&me), cptr->name, cptr->serv->timestamp,
860 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr), NumServCap(cptr),
861 cptr->sockhost, cptr->info);
864 ":%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :[%s] %s", me.name,
865 cptr->name, cptr->serv->timestamp,
866 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr), NumServCap(cptr),
867 cptr->sockhost, cptr->info);
871 if (Protocol(acptr) > 9)
872 sendto_one(acptr, "%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
873 NumServ(&me), cptr->name, cptr->serv->timestamp,
874 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
875 NumServCap(cptr), cptr->info);
877 sendto_one(acptr, ":%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
878 me.name, cptr->name, cptr->serv->timestamp,
879 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
880 NumServCap(cptr), cptr->info);
885 * Pass on my client information to the new server
887 * First, pass only servers (idea is that if the link gets
888 * cancelled beacause the server was already there,
889 * there are no NICK's to be cancelled...). Of course,
890 * if cancellation occurs, all this info is sent anyway,
891 * and I guess the link dies when a read is attempted...? --msa
893 * Note: Link cancellation to occur at this point means
894 * that at least two servers from my fragment are building
895 * up connection this other fragment at the same time, it's
896 * a race condition, not the normal way of operation...
899 aconf = cptr->serv->nline;
900 for (acptr = &me; acptr; acptr = acptr->prev)
902 /* acptr->from == acptr for acptr == cptr */
903 if (acptr->from == cptr)
908 (Protocol(acptr) > 9) ? (IsBurst(acptr) ? "J" : "P") : "P0";
909 if (match(my_name_for_link(me.name, aconf), acptr->name) == 0)
911 split = (MyConnect(acptr) && strCasediff(acptr->name, acptr->sockhost) &&
912 strnCasecmp(acptr->info, "JUPE", 4));
915 if (Protocol(cptr) > 9)
917 "%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :[%s] %s",
918 NumServ(acptr->serv->up), acptr->name,
919 acptr->hopcount + 1, acptr->serv->timestamp,
920 protocol_str, Protocol(acptr),
921 NumServCap(acptr), acptr->sockhost, acptr->info);
924 ":%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :[%s] %s",
925 acptr->serv->up->name, acptr->name,
926 acptr->hopcount + 1, acptr->serv->timestamp,
927 protocol_str, Protocol(acptr),
928 NumServCap(acptr), acptr->sockhost, acptr->info);
932 if (Protocol(cptr) > 9)
934 "%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
935 NumServ(acptr->serv->up), acptr->name,
936 acptr->hopcount + 1, acptr->serv->timestamp,
937 protocol_str, Protocol(acptr), NumServCap(acptr), acptr->info);
940 ":%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
941 acptr->serv->up->name, acptr->name,
942 acptr->hopcount + 1, acptr->serv->timestamp,
943 protocol_str, Protocol(acptr), NumServCap(acptr), acptr->info);
948 for (acptr = &me; acptr; acptr = acptr->prev)
950 /* acptr->from == acptr for acptr == cptr */
951 if (acptr->from == cptr)
955 if (Protocol(cptr) < 10)
958 * IsUser(x) is true only *BOTH* NICK and USER have
959 * been received. -avalon
960 * Or only NICK in new format. --Run
962 sendto_one(cptr, ":%s NICK %s %d " TIME_T_FMT " %s %s %s :%s",
963 acptr->user->server->name,
964 acptr->name, acptr->hopcount + 1, acptr->lastnick,
965 acptr->user->username, acptr->user->host,
966 acptr->user->server->name, acptr->info);
967 send_umode(cptr, acptr, 0, SEND_UMODES);
968 send_user_joins(cptr, acptr);
973 char *s = umode_str(acptr);
974 sendto_one(cptr, *s ?
975 "%s NICK %s %d " TIME_T_FMT " %s %s +%s %s %s%s :%s" :
976 "%s NICK %s %d " TIME_T_FMT " %s %s %s%s %s%s :%s",
977 NumServ(acptr->user->server),
978 acptr->name, acptr->hopcount + 1, acptr->lastnick,
979 acptr->user->username, acptr->user->host,
980 s, inttobase64(xxx_buf, ntohl(acptr->ip.s_addr), 6),
981 NumNick(acptr), acptr->info);
986 * Last, send the BURST.
987 * (Or for 2.9 servers: pass all channels plus statuses)
990 Reg1 aChannel *chptr;
991 for (chptr = channel; chptr; chptr = chptr->nextch)
992 send_channel_modes(cptr, chptr);
994 if (Protocol(cptr) >= 10)
995 sendto_one(cptr, "%s END_OF_BURST", NumServ(&me));
1002 * parv[0] = sender prefix
1003 * parv[parc-1] = text
1005 int m_error(aClient *cptr, aClient *sptr, int parc, char *parv[])
1009 para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
1011 Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", sptr->name, para));
1013 * Ignore error messages generated by normal user clients
1014 * (because ill-behaving user clients would flood opers
1015 * screen otherwise). Pass ERROR's from other sources to
1016 * the local operator...
1020 if (IsUnknown(cptr))
1021 return exit_client_msg(cptr, cptr, &me, "Register first");
1024 sendto_ops("ERROR :from %s -- %s", get_client_name(cptr, FALSE), para);
1026 sendto_ops("ERROR :from %s via %s -- %s",
1027 sptr->name, get_client_name(cptr, FALSE), para);
1031 RunFree(sptr->serv->last_error_msg);
1032 DupString(sptr->serv->last_error_msg, para);
1039 * m_end_of_burst - Added Xorath 6-14-96, rewritten by Run 24-7-96
1040 * - and fixed by record and Kev 8/1/96
1041 * - and really fixed by Run 15/8/96 :p
1042 * This the last message in a net.burst.
1043 * It clears a flag for the server sending the burst.
1045 * parv[0] - sender prefix
1047 int m_end_of_burst(aClient *cptr, aClient *sptr, int UNUSED(parc),
1048 char **UNUSED(parv))
1050 if (!IsServer(sptr))
1053 sendto_op_mask(SNO_NETWORK, "Completed net.burst from %s.", sptr->name);
1055 sendto_serv_butone(cptr, "%s END_OF_BURST", NumServ(sptr));
1057 sendto_highprot_butone(cptr, 10, "%s END_OF_BURST", NumServ(sptr));
1061 if (MyConnect(sptr))
1062 sendto_one(sptr, "%s EOB_ACK", NumServ(&me));
1068 * m_end_of_burst_ack
1070 * This the acknowledge message of the `END_OF_BURST' message.
1071 * It clears a flag for the server receiving the burst.
1073 * parv[0] - sender prefix
1075 int m_end_of_burst_ack(aClient *cptr, aClient *sptr, int UNUSED(parc),
1076 char **UNUSED(parv))
1078 if (!IsServer(sptr))
1081 sendto_op_mask(SNO_NETWORK, "%s acknowledged end of net.burst.", sptr->name);
1083 sendto_serv_butone(cptr, "%s EOB_ACK", NumServ(sptr));
1085 sendto_highprot_butone(cptr, 10, "%s EOB_ACK", NumServ(sptr));
1087 ClearBurstAck(sptr);
1095 * Writes to all +g users; for sending wall type debugging/anti-hack info.
1096 * Added 23 Apr 1998 --Run
1098 * parv[0] - sender prefix
1099 * parv[parc-1] - message text
1101 int m_desynch(aClient *cptr, aClient *sptr, int parc, char *parv[])
1103 if (IsServer(sptr) && parc >= 2)
1107 /* Send message to local +g clients as if it were a wallops */
1108 sprintf_irc(sendbuf, ":%s WALLOPS :%s", parv[0], parv[parc - 1]);
1109 for (i = 0; i <= highest_fd; i++)
1110 if ((acptr = loc_clients[i]) && !IsServer(acptr) && !IsMe(acptr) &&
1112 sendbufto_one(acptr);
1113 /* Send message to remote +g clients */
1114 sendto_g_serv_butone(cptr, "%s DESYNCH :%s", NumServ(sptr), parv[parc - 1]);