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();
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, FALSE));
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, FALSE));
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.", cptr->name);
270 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
273 if (check_server(cptr))
276 sendto_ops("Received unauthorized connection from %s.", cptr->name);
277 return exit_client(cptr, cptr, &me, "No C/N conf lines");
284 if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
288 sendto_ops("Access denied. No N line for server %s", inpath);
289 return exit_client_msg(cptr, cptr, &me,
290 "Access denied. No N line for server %s", inpath);
292 sendto_ops("General C/N: line active: No N line for server %s", inpath);
294 find_conf(cptr->confs, "general.undernet.org", CONF_NOCONNECT_SERVER);
296 find_conf(cptr->confs, "general.undernet.org", CONF_CONNECT_SERVER);
297 if (!aconf || !bconf)
299 sendto_ops("Neither C/N lines for server %s nor "
300 "\"general.undernet.org\"", inpath);
301 return exit_client_msg(cptr, cptr, &me,
302 "No C/N lines for server %s", inpath);
306 else if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER)))
309 sendto_ops("Only N (no C) field for server %s", inpath);
310 return exit_client_msg(cptr, cptr, &me,
311 "Only N (no C) field for server %s", inpath);
314 #ifdef CRYPT_LINK_PASSWORD
315 /* passwd may be NULL. Head it off at the pass... */
320 salt[0] = aconf->passwd[0];
321 salt[1] = aconf->passwd[1];
323 encr = crypt(cptr->passwd, salt);
329 #endif /* CRYPT_LINK_PASSWORD */
331 if (*aconf->passwd && !!strcmp(aconf->passwd, encr))
334 sendto_ops("Access denied (passwd mismatch) %s", inpath);
335 return exit_client_msg(cptr, cptr, &me,
336 "No Access (passwd mismatch) %s", inpath);
338 #endif /* not GODMODE */
339 memset(cptr->passwd, 0, sizeof(cptr->passwd));
342 for (i = 0; i <= highest_fd; i++)
343 if (loc_clients[i] && IsServer(loc_clients[i]))
350 if (!IsUnknown(cptr))
352 s = strchr(aconf->host, '@');
353 *s = '\0'; /* should never be NULL */
354 Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]",
355 aconf->host, cptr->username));
356 if (match(aconf->host, cptr->username))
360 sendto_ops("Username mismatch [%s]v[%s] : %s",
361 aconf->host, cptr->username, get_client_name(cptr, FALSE));
362 return exit_client(cptr, cptr, &me, "Bad Username");
369 * We want to find IsConnecting() and IsHandshake() too,
371 * The second finds collisions with numeric representation of existing
372 * servers - these shouldn't happen anymore when all upgraded to 2.10.
375 while ((acptr = FindClient(host)) ||
376 (parc > 7 && (acptr = FindNServer(parv[6]))))
379 * This link is trying feed me a server that I already have
380 * access through another path
382 * Do not allow Uworld to do this.
383 * Do not allow servers that are juped.
384 * Do not allow servers that have older link timestamps
386 * Do not allow servers that use the same numeric as an existing
387 * server, but have a different name.
389 * If my ircd.conf sucks, I can try to connect to myself:
392 return exit_client_msg(cptr, cptr, &me,
393 "nick collision with me (%s)", host);
395 * Detect wrong numeric.
397 if (strCasediff(acptr->name, host))
399 sendto_serv_butone(cptr,
400 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
401 me.name, acptr->name, host);
402 return exit_client_msg(cptr, cptr, &me,
403 "NUMERIC collision between %s and %s."
404 " Is your server numeric correct ?", host, acptr->name);
407 * Kill our try, if we had one.
409 if (IsConnecting(acptr))
411 if (!active_lh_line && exit_client(cptr, acptr, &me,
412 "Just connected via another link") == CPTR_KILLED)
415 * We can have only ONE 'IsConnecting', 'IsHandshake' or
416 * 'IsServer', because new 'IsConnecting's are refused to
417 * the same server if we already had it.
422 * Avoid other nick collisions...
423 * This is a doubtfull test though, what else would it be
424 * when it has a server.name ?
426 else if (!IsServer(acptr) && !IsHandshake(acptr))
427 return exit_client_msg(cptr, cptr, &me,
428 "Nickname %s already exists!", host);
430 * Our new server might be a juped server,
431 * or someone trying abuse a second Uworld:
433 else if (IsServer(acptr) && (strnCasecmp(acptr->info, "JUPE", 4) == 0 ||
434 find_conf_host(cptr->confs, acptr->name, CONF_UWORLD)))
437 return exit_client(cptr, sptr, &me, acptr->info);
438 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
439 me.name, parv[0], parv[1], cptr->name);
440 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
443 * Of course we find the handshake this link was before :)
445 else if (IsHandshake(acptr) && acptr == cptr)
448 * Here we have a server nick collision...
449 * We don't want to kill the link that was last /connected,
450 * but we neither want to kill a good (old) link.
451 * Therefor we kill the second youngest link.
455 aClient *c2ptr = NULL, *c3ptr = acptr;
456 aClient *ac2ptr, *ac3ptr;
458 /* Search youngest link: */
459 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
460 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
464 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
465 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
468 if (timestamp > c3ptr->serv->timestamp)
471 c2ptr = acptr; /* Make sure they differ */
473 /* Search second youngest link: */
474 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
475 if (ac2ptr != c3ptr &&
476 ac2ptr->serv->timestamp >
477 (c2ptr ? c2ptr->serv->timestamp : timestamp))
481 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
482 if (ac2ptr != c3ptr &&
483 ac2ptr->serv->timestamp >
484 (c2ptr ? c2ptr->serv->timestamp : timestamp))
487 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
489 /* If timestamps are equal, decide which link to break
492 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
493 (c3ptr ? c3ptr->serv->timestamp : timestamp))
500 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
505 n2up = IsServer(sptr) ? sptr->name : me.name;
510 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
515 n3up = IsServer(sptr) ? sptr->name : me.name;
517 if (strcmp(n2, n2up) > 0)
519 if (strcmp(n3, n3up) > 0)
521 if (strcmp(n3, n2) > 0)
528 /* Now squit the second youngest link: */
530 return exit_new_server(cptr, sptr, host, timestamp,
531 "server %s already exists and is %ld seconds younger.",
532 host, (long)acptr->serv->timestamp - (long)timestamp);
533 else if (c2ptr->from == cptr || IsServer(sptr))
535 aClient *killedptrfrom = c2ptr->from;
539 * If the L: or H: line also gets rid of this link,
540 * we sent just one squit.
542 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
545 * If breaking the loop here solves the L: or H:
546 * line problem, we don't squit that.
548 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
553 * If we still have a L: or H: line problem,
554 * we prefer to squit the new server, solving
555 * loop and L:/H: line problem with only one squit.
562 * If the new server was introduced by a server that caused a
563 * Ghost less then 20 seconds ago, this is probably also
564 * a Ghost... (20 seconds is more then enough because all
565 * SERVER messages are at the beginning of a net.burst). --Run
567 if (now - cptr->serv->ghost < 20)
569 killedptrfrom = acptr->from;
570 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
573 else if (exit_client_msg(cptr, c2ptr, &me,
574 "Loop <-- %s (new link is %ld seconds younger)", host,
575 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
576 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
579 * Did we kill the incoming server off already ?
581 if (killedptrfrom == cptr)
588 if (LHcptr && a_kills_b_too(LHcptr, acptr))
590 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
599 * We can't believe it is a lagged server message
600 * when it directly connects to us...
601 * kill the older link at the ghost, rather then
602 * at the second youngest link, assuming it isn't
605 ghost = now; /* Mark that it caused a ghost */
606 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
616 return exit_new_server(cptr, sptr, host, timestamp,
617 (active_lh_line == 2) ?
618 "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
620 lhconf ? (lhconf->host ? lhconf->host : "*") : "!");
623 register int killed = a_kills_b_too(LHcptr, sptr);
624 if (active_lh_line < 3)
626 if (exit_client_msg(cptr, LHcptr, &me,
627 (active_lh_line == 2) ?
628 "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
630 lhconf ? (lhconf->host ? lhconf->host : "*") : "!") == CPTR_KILLED)
636 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
640 * Did we kill the incoming server off already ?
650 * Server is informing about a new server behind
651 * this link. Create REMOTE server structure,
652 * add it to list and propagate word to my other
656 acptr = make_client(cptr, STAT_SERVER);
658 acptr->serv->prot = prot;
659 acptr->serv->timestamp = timestamp;
660 acptr->hopcount = hop;
661 strncpy(acptr->name, host, sizeof(acptr->name) - 1);
662 strncpy(acptr->info, info, sizeof(acptr->info) - 1);
663 acptr->serv->up = sptr;
664 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
665 /* Use cptr, because we do protocol 9 -> 10 translation
666 for numeric nicks ! */
667 SetServerYXX(cptr, acptr, parv[6]);
668 Count_newremoteserver(nrof);
669 if (Protocol(acptr) < 10)
670 acptr->flags |= FLAGS_TS8;
671 add_client_to_list(acptr);
675 if (Protocol(acptr) > 9)
677 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
678 sptr->name, acptr->name);
682 * Old sendto_serv_but_one() call removed because we now need to send
683 * different names to different servers (domain name matching).
685 for (i = 0; i <= highest_fd; i++)
687 if (!(bcptr = loc_clients[i]) || !IsServer(bcptr) ||
688 bcptr == cptr || IsMe(bcptr))
690 if (!(cconf = bcptr->serv->nline))
692 sendto_ops("Lost N-line for %s on %s. Closing",
694 return exit_client(cptr, cptr, &me, "Lost N line");
696 if (match(my_name_for_link(me.name, cconf), acptr->name) == 0)
698 if (Protocol(bcptr) > 9)
699 sendto_one(bcptr, "%s SERVER %s %d 0 %s %s %s%s 0 :%s",
700 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
701 NumServCap(acptr), acptr->info);
703 sendto_one(bcptr, ":%s SERVER %s %d 0 %s %s %s%s 0 :%s",
704 parv[0], acptr->name, hop + 1, parv[4], parv[5],
705 NumServCap(acptr), acptr->info);
710 if (IsUnknown(cptr) || IsHandshake(cptr))
713 cptr->serv->timestamp = timestamp;
714 cptr->serv->prot = prot;
715 cptr->serv->ghost = ghost;
716 SetServerYXX(cptr, cptr, parv[6]);
717 if (start_timestamp > 780000000)
719 #ifndef RELIABLE_CLOCK
721 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
722 TIME_T_FMT, me.serv->timestamp, start_timestamp);
723 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
724 TIME_T_FMT " ; difference %ld",
725 recv_time, timestamp, timestamp - recv_time);
727 if (start_timestamp < me.serv->timestamp)
729 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
730 start_timestamp, me.serv->timestamp);
731 me.serv->timestamp = start_timestamp;
732 TSoffset += timestamp - recv_time;
733 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
735 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
736 cptr->serv->timestamp = TStime();
738 else if (timestamp != recv_time)
739 /* Equal start times, we have a collision. Let the connected-to server
740 decide. This assumes leafs issue more than half of the connection
744 cptr->serv->timestamp = TStime();
745 else if (IsHandshake(cptr))
747 sendto_ops("clock adjusted by adding %d",
748 (int)(timestamp - recv_time));
749 TSoffset += timestamp - recv_time;
752 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
753 if (start_timestamp < me.serv->timestamp)
754 me.serv->timestamp = start_timestamp;
756 cptr->serv->timestamp = TStime();
760 ret = m_server_estab(cptr, aconf, bconf);
764 #ifdef RELIABLE_CLOCK
765 if (abs(cptr->serv->timestamp - recv_time) > 30)
767 sendto_ops("Connected to a net with a timestamp-clock"
768 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
769 " this.", timestamp - recv_time);
770 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
771 me.name, TStime(), me.name);
781 * May only be called after a SERVER was received from cptr,
782 * and thus make_server was called, and serv->prot set. --Run
784 int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf)
790 split = (strCasediff(cptr->name, cptr->sockhost)
791 && strnCasecmp(cptr->info, "JUPE", 4));
797 if (bconf->passwd[0])
798 sendto_one(cptr, "PASS :%s", bconf->passwd);
800 * Pass my info to the new server
802 sendto_one(cptr, "SERVER %s 1 " TIME_T_FMT " " TIME_T_FMT " J%s %s%s :%s",
803 my_name_for_link(me.name, aconf), me.serv->timestamp,
804 cptr->serv->timestamp, MAJOR_PROTOCOL, NumServCap(&me),
805 (me.info[0]) ? (me.info) : "IRCers United");
807 IPcheck_connect_fail(cptr); /* Don't charge this IP# for connecting */
810 det_confs_butmask(cptr,
811 CONF_LEAF | CONF_HUB | CONF_NOCONNECT_SERVER | CONF_UWORLD);
813 if (!IsHandshake(cptr))
816 Count_unknownbecomesserver(nrof);
817 if (Protocol(cptr) > 9)
820 cptr->flags |= FLAGS_TS8;
822 if (cptr->serv->user && *cptr->serv->by &&
823 (acptr = findNUser(cptr->serv->by)) && acptr->user == cptr->serv->user)
825 if (MyUser(acptr) || Protocol(acptr->from) < 10)
826 sendto_one(acptr, ":%s NOTICE %s :Link with %s established.",
827 me.name, acptr->name, inpath);
829 sendto_one(acptr, "%s NOTICE %s%s :Link with %s established.",
830 NumServ(&me), NumNick(acptr), inpath);
834 sendto_lops_butone(acptr, "Link with %s established.", inpath);
835 cptr->serv->up = &me;
836 cptr->serv->updown = add_dlink(&me.serv->down, cptr);
837 cptr->serv->nline = aconf;
838 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", me.name, cptr->name);
841 * Old sendto_serv_but_one() call removed because we now
842 * need to send different names to different servers
843 * (domain name matching) Send new server to other servers.
845 for (i = 0; i <= highest_fd; i++)
847 if (!(acptr = loc_clients[i]) || !IsServer(acptr) ||
848 acptr == cptr || IsMe(acptr))
850 if ((aconf = acptr->serv->nline) &&
851 !match(my_name_for_link(me.name, aconf), cptr->name))
855 if (Protocol(acptr) > 9)
857 "%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
858 NumServ(&me), cptr->name, cptr->serv->timestamp,
859 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr), NumServCap(cptr),
863 ":%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s", me.name,
864 cptr->name, cptr->serv->timestamp,
865 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr), NumServCap(cptr),
870 if (Protocol(acptr) > 9)
871 sendto_one(acptr, "%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
872 NumServ(&me), cptr->name, cptr->serv->timestamp,
873 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
874 NumServCap(cptr), cptr->info);
876 sendto_one(acptr, ":%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
877 me.name, cptr->name, cptr->serv->timestamp,
878 (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
879 NumServCap(cptr), cptr->info);
884 * Pass on my client information to the new server
886 * First, pass only servers (idea is that if the link gets
887 * cancelled beacause the server was already there,
888 * there are no NICK's to be cancelled...). Of course,
889 * if cancellation occurs, all this info is sent anyway,
890 * and I guess the link dies when a read is attempted...? --msa
892 * Note: Link cancellation to occur at this point means
893 * that at least two servers from my fragment are building
894 * up connection this other fragment at the same time, it's
895 * a race condition, not the normal way of operation...
898 aconf = cptr->serv->nline;
899 for (acptr = &me; acptr; acptr = acptr->prev)
901 /* acptr->from == acptr for acptr == cptr */
902 if (acptr->from == cptr)
907 (Protocol(acptr) > 9) ? (IsBurst(acptr) ? "J" : "P") : "P0";
908 if (match(my_name_for_link(me.name, aconf), acptr->name) == 0)
910 split = (MyConnect(acptr) && strCasediff(acptr->name, acptr->sockhost) &&
911 strnCasecmp(acptr->info, "JUPE", 4));
914 if (Protocol(cptr) > 9)
916 "%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
917 NumServ(acptr->serv->up), acptr->name,
918 acptr->hopcount + 1, acptr->serv->timestamp,
919 protocol_str, Protocol(acptr),
920 NumServCap(acptr), acptr->info);
923 ":%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
924 acptr->serv->up->name, acptr->name,
925 acptr->hopcount + 1, acptr->serv->timestamp,
926 protocol_str, Protocol(acptr),
927 NumServCap(acptr), acptr->info);
931 if (Protocol(cptr) > 9)
933 "%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
934 NumServ(acptr->serv->up), acptr->name,
935 acptr->hopcount + 1, acptr->serv->timestamp,
936 protocol_str, Protocol(acptr), NumServCap(acptr), acptr->info);
939 ":%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
940 acptr->serv->up->name, acptr->name,
941 acptr->hopcount + 1, acptr->serv->timestamp,
942 protocol_str, Protocol(acptr), NumServCap(acptr), acptr->info);
947 for (acptr = &me; acptr; acptr = acptr->prev)
949 /* acptr->from == acptr for acptr == cptr */
950 if (acptr->from == cptr)
954 if (Protocol(cptr) < 10)
957 * IsUser(x) is true only *BOTH* NICK and USER have
958 * been received. -avalon
959 * Or only NICK in new format. --Run
961 sendto_one(cptr, ":%s NICK %s %d " TIME_T_FMT " %s %s %s :%s",
962 acptr->user->server->name,
963 acptr->name, acptr->hopcount + 1, acptr->lastnick,
964 acptr->user->username, acptr->user->host,
965 acptr->user->server->name, acptr->info);
966 send_umode(cptr, acptr, 0, SEND_UMODES);
967 send_user_joins(cptr, acptr);
972 char *s = umode_str(acptr);
973 sendto_one(cptr, *s ?
974 "%s NICK %s %d " TIME_T_FMT " %s %s +%s %s %s%s :%s" :
975 "%s NICK %s %d " TIME_T_FMT " %s %s %s%s %s%s :%s",
976 NumServ(acptr->user->server),
977 acptr->name, acptr->hopcount + 1, acptr->lastnick,
978 acptr->user->username, acptr->user->host,
979 s, inttobase64(xxx_buf, ntohl(acptr->ip.s_addr), 6),
980 NumNick(acptr), acptr->info);
985 * Last, send the BURST.
986 * (Or for 2.9 servers: pass all channels plus statuses)
989 Reg1 aChannel *chptr;
990 for (chptr = channel; chptr; chptr = chptr->nextch)
991 send_channel_modes(cptr, chptr);
993 if (Protocol(cptr) >= 10)
994 sendto_one(cptr, "%s END_OF_BURST", NumServ(&me));
1001 * parv[0] = sender prefix
1002 * parv[parc-1] = text
1004 int m_error(aClient *cptr, aClient *sptr, int parc, char *parv[])
1008 para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
1010 Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", sptr->name, para));
1012 * Ignore error messages generated by normal user clients
1013 * (because ill-behaving user clients would flood opers
1014 * screen otherwise). Pass ERROR's from other sources to
1015 * the local operator...
1019 if (IsUnknown(cptr))
1020 return exit_client_msg(cptr, cptr, &me, "Register first");
1023 sendto_ops("ERROR :from %s -- %s", cptr->name, para);
1025 sendto_ops("ERROR :from %s via %s -- %s",
1026 sptr->name, cptr->name, para);
1030 RunFree(sptr->serv->last_error_msg);
1031 DupString(sptr->serv->last_error_msg, para);
1038 * m_end_of_burst - Added Xorath 6-14-96, rewritten by Run 24-7-96
1039 * - and fixed by record and Kev 8/1/96
1040 * - and really fixed by Run 15/8/96 :p
1041 * This the last message in a net.burst.
1042 * It clears a flag for the server sending the burst.
1044 * parv[0] - sender prefix
1046 int m_end_of_burst(aClient *cptr, aClient *sptr, int UNUSED(parc),
1047 char **UNUSED(parv))
1049 if (!IsServer(sptr))
1052 sendto_op_mask(SNO_NETWORK, "Completed net.burst from %s.", sptr->name);
1054 sendto_serv_butone(cptr, "%s END_OF_BURST", NumServ(sptr));
1056 sendto_highprot_butone(cptr, 10, "%s END_OF_BURST", NumServ(sptr));
1060 if (MyConnect(sptr))
1061 sendto_one(sptr, "%s EOB_ACK", NumServ(&me));
1067 * m_end_of_burst_ack
1069 * This the acknowledge message of the `END_OF_BURST' message.
1070 * It clears a flag for the server receiving the burst.
1072 * parv[0] - sender prefix
1074 int m_end_of_burst_ack(aClient *cptr, aClient *sptr, int UNUSED(parc),
1075 char **UNUSED(parv))
1077 if (!IsServer(sptr))
1080 sendto_op_mask(SNO_NETWORK, "%s acknowledged end of net.burst.", sptr->name);
1082 sendto_serv_butone(cptr, "%s EOB_ACK", NumServ(sptr));
1084 sendto_highprot_butone(cptr, 10, "%s EOB_ACK", NumServ(sptr));
1086 ClearBurstAck(sptr);
1094 * Writes to all +g users; for sending wall type debugging/anti-hack info.
1095 * Added 23 Apr 1998 --Run
1097 * parv[0] - sender prefix
1098 * parv[parc-1] - message text
1100 int m_desynch(aClient *cptr, aClient *sptr, int parc, char *parv[])
1102 if (IsServer(sptr) && parc >= 2)
1106 /* Send message to local +g clients as if it were a wallops */
1107 sprintf_irc(sendbuf, ":%s WALLOPS :%s", parv[0], parv[parc - 1]);
1108 for (i = 0; i <= highest_fd; i++)
1109 if ((acptr = loc_clients[i]) && !IsServer(acptr) && !IsMe(acptr) &&
1111 sendbufto_one(acptr);
1112 /* Send message to remote +g clients */
1113 sendto_g_serv_butone(cptr, "%s DESYNCH :%s", NumServ(sptr), parv[parc - 1]);