2 * IRC - Internet Relay Chat, ircd/m_server.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.
27 * m_functions execute protocol messages on this server:
29 * cptr is always NON-NULL, pointing to a *LOCAL* client
30 * structure (with an open socket connected!). This
31 * identifies the physical socket where the message
32 * originated (or which caused the m_function to be
33 * executed--some m_functions may call others...).
35 * sptr is the source of the message, defined by the
36 * prefix part of the message if present. If not
37 * or prefix not found, then sptr==cptr.
39 * (!IsServer(cptr)) => (cptr == sptr), because
40 * prefixes are taken *only* from servers...
43 * (sptr == cptr) => the message didn't
46 * (sptr != cptr && IsServer(sptr) means
47 * the prefix specified servername. (?)
49 * (sptr != cptr && !IsServer(sptr) means
50 * that message originated from a remote
55 * (!IsServer(sptr)) means that, sptr can safely
56 * taken as defining the target structure of the
57 * message in this server.
59 * *Always* true (if 'parse' and others are working correct):
61 * 1) sptr->from == cptr (note: cptr->from == cptr)
63 * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64 * *cannot* be a local connection, unless it's
65 * actually cptr!). [MyConnect(x) should probably
66 * be defined as (x == x->from) --msa ]
68 * parc number of variable parameter strings (if zero,
69 * parv is allowed to be NULL)
71 * parv a NULL terminated list of parameter pointers,
73 * parv[0], sender (prefix string), if not present
74 * this points to an empty string.
75 * parv[1]...parv[parc-1]
76 * pointers to additional parameters
77 * parv[parc] == NULL, *always*
79 * note: it is guaranteed that parv[0]..parv[parc-1] are all
86 * No need to include handlers.h here the signatures must match
87 * and we don't need to force a rebuild of all the handlers everytime
88 * we add a new one to the list. --Bleep
96 #include "ircd_features.h"
97 #include "ircd_reply.h"
98 #include "ircd_string.h"
104 #include "numnicks.h"
105 #include "querycmds.h"
112 #include "userload.h"
119 * mr_server - registration message handler
121 * parv[0] = sender prefix
122 * parv[1] = servername
124 * parv[3] = start timestamp
125 * parv[4] = link timestamp
126 * parv[5] = major protocol version: P09/P10
127 * parv[parc-1] = serverinfo
129 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
130 * numeric nick mask of this server.
131 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
133 int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
137 char info[REALLEN + 1];
139 struct Client* acptr;
140 struct Client* bcptr;
141 struct Client* LHcptr = 0;
142 struct ConfItem* aconf = 0;
143 struct ConfItem* lhconf = 0;
144 struct Jupe* ajupe = 0;
147 int active_lh_line = 0;
149 time_t start_timestamp;
150 time_t timestamp = 0;
154 if (IsUserPort(cptr))
155 return exit_client_msg(cptr, cptr, &me,
156 "Cannot connect a server to a user port");
158 recv_time = TStime();
163 need_more_params(sptr, "SERVER");
164 return exit_client(cptr, cptr, &me, "Need more parameters");
168 if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
169 return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
171 log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "SERVER: %s %s[%s]", parv[1],
172 cli_sockhost(cptr), cli_sock_ip(cptr));
177 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
178 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
180 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
183 prot = atoi(parv[5] + 1);
184 if (prot > atoi(MAJOR_PROTOCOL))
185 prot = atoi(MAJOR_PROTOCOL);
187 * Because the previous test is only in 2.10, the following is needed
188 * till all servers are 2.10:
190 if (IsServer(cptr) && prot > Protocol(cptr))
191 prot = Protocol(cptr);
193 start_timestamp = atoi(parv[3]);
194 timestamp = atoi(parv[4]);
195 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
196 host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
198 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
200 return exit_client_msg(cptr, sptr, &me,
201 "Bogus timestamps (%s %s)", parv[3], parv[4]);
203 ircd_strncpy(info, parv[parc - 1], REALLEN);
204 info[REALLEN] = '\0';
205 if (prot < atoi(MINOR_PROTOCOL)) {
206 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
207 "(%s) from %s", parv[5], cli_name(cptr));
208 return exit_new_server(cptr, sptr, host, timestamp,
209 "Incompatible protocol: %s", parv[5]);
212 * Check for "FRENCH " infection ;-) (actually this should
213 * be replaced with routine to check the hostname syntax in
214 * general). [ This check is still needed, even after the parse
215 * is fixed, because someone can send "SERVER :foo bar " ].
216 * Also, changed to check other "difficult" characters, now
217 * that parse lets all through... --msa
219 if (strlen(host) > HOSTLEN)
220 host[HOSTLEN] = '\0';
222 for (ch = host; *ch; ch++) {
223 if (*ch <= ' ' || *ch > '~')
226 if (*ch || !strchr(host, '.')) {
227 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
228 host, cli_name(cptr));
229 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
235 * A local server introduces a new server behind this link.
236 * Check if this is allowed according L:, H: and Q: lines.
239 return exit_client_msg(cptr, cptr, &me,
240 "No server info specified for %s", host);
242 * See if the newly found server is behind a guaranteed
243 * leaf (L-line). If so, close the link.
245 if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
246 (!lhconf->port || (hop > lhconf->port)))
249 * L: lines normally come in pairs, here we try to
250 * make sure that the oldest link is squitted, not
254 if (timestamp <= cli_serv(cptr)->timestamp)
255 LHcptr = 0; /* Kill incoming server */
257 LHcptr = cptr; /* Squit ourselfs */
259 else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
260 (lhconf->port && (hop > lhconf->port)))
262 struct Client *ac3ptr;
264 /* Look for net junction causing this: */
265 LHcptr = 0; /* incoming server */
266 if (*parv[5] != 'J') {
267 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
268 if (IsJunction(ac3ptr)) {
277 if (IsUnknown(cptr) || IsHandshake(cptr))
282 * A local link that is still in undefined state wants
283 * to be a SERVER. Check if this is allowed and change
284 * status accordingly...
287 * If there is more then one server on the same machine
288 * that we try to connect to, it could be that the /CONNECT
289 * <mask> caused this connect to be put at the wrong place
290 * in the hashtable. --Run
291 * Same thing for Unknown connections that first send NICK.
293 * Better check if the two strings are (caseless) identical
294 * and not mess with hash internals.
297 if (!EmptyString(cli_name(cptr)) &&
298 (IsUnknown(cptr) || IsHandshake(cptr)) &&
299 0 != ircd_strcmp(cli_name(cptr), host))
300 hChangeClient(cptr, host);
301 ircd_strncpy(cli_name(cptr), host, HOSTLEN);
302 ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
303 cli_hopcount(cptr) = hop;
305 /* check connection rules */
306 if (0 != conf_eval_crule(host, CRULE_ALL)) {
307 ServerStats->is_ref++;
308 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
309 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
312 if (conf_check_server(cptr)) {
313 ++ServerStats->is_ref;
314 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
315 "from %s.", cli_name(cptr));
316 return exit_client(cptr, cptr, &me, "No C:line");
319 host = cli_name(cptr);
323 if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
324 ++ServerStats->is_ref;
325 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
326 "server %s", cli_name(cptr));
327 return exit_client_msg(cptr, cptr, &me,
328 "Access denied. No conf line for server %s", cli_name(cptr));
330 encr = cli_passwd(cptr);
332 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
333 ++ServerStats->is_ref;
334 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
336 return exit_client_msg(cptr, cptr, &me,
337 "No Access (passwd mismatch) %s", cli_name(cptr));
340 memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
342 if (!feature_bool(FEAT_HUB)) {
343 for (i = 0; i <= HighestFd; i++)
344 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
353 * We want to find IsConnecting() and IsHandshake() too,
355 * The second finds collisions with numeric representation of existing
356 * servers - these shouldn't happen anymore when all upgraded to 2.10.
359 while ((acptr = FindClient(host)) ||
360 (parc > 7 && (acptr = FindNServer(parv[6]))))
363 * This link is trying feed me a server that I already have
364 * access through another path
366 * Do not allow Uworld to do this.
367 * Do not allow servers that are juped.
368 * Do not allow servers that have older link timestamps
370 * Do not allow servers that use the same numeric as an existing
371 * server, but have a different name.
373 * If my ircd.conf sucks, I can try to connect to myself:
376 return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
378 * Detect wrong numeric.
380 if (0 != ircd_strcmp(cli_name(acptr), host)) {
381 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
382 ":SERVER Numeric Collision: %s != %s",
383 cli_name(acptr), host);
384 return exit_client_msg(cptr, cptr, &me,
385 "NUMERIC collision between %s and %s."
386 " Is your server numeric correct ?", host, cli_name(acptr));
389 * Kill our try, if we had one.
391 if (IsConnecting(acptr))
393 if (!active_lh_line && exit_client(cptr, acptr, &me,
394 "Just connected via another link") == CPTR_KILLED)
397 * We can have only ONE 'IsConnecting', 'IsHandshake' or
398 * 'IsServer', because new 'IsConnecting's are refused to
399 * the same server if we already had it.
404 * Avoid other nick collisions...
405 * This is a doubtfull test though, what else would it be
406 * when it has a server.name ?
408 else if (!IsServer(acptr) && !IsHandshake(acptr))
409 return exit_client_msg(cptr, cptr, &me,
410 "Nickname %s already exists!", host);
412 * Our new server might be a juped server,
413 * or someone trying abuse a second Uworld:
415 else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
416 find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
419 return exit_client(cptr, sptr, &me, cli_info(acptr));
420 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
421 ":Received :%s SERVER %s from %s !?!", parv[0],
422 parv[1], cli_name(cptr));
423 return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
426 * Of course we find the handshake this link was before :)
428 else if (IsHandshake(acptr) && acptr == cptr)
431 * Here we have a server nick collision...
432 * We don't want to kill the link that was last /connected,
433 * but we neither want to kill a good (old) link.
434 * Therefor we kill the second youngest link.
438 struct Client* c2ptr = 0;
439 struct Client* c3ptr = acptr;
440 struct Client* ac2ptr;
441 struct Client* ac3ptr;
443 /* Search youngest link: */
444 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
445 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
449 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
450 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
453 if (timestamp > cli_serv(c3ptr)->timestamp)
456 c2ptr = acptr; /* Make sure they differ */
458 /* Search second youngest link: */
459 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
460 if (ac2ptr != c3ptr &&
461 cli_serv(ac2ptr)->timestamp >
462 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
466 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
467 if (ac2ptr != c3ptr &&
468 cli_serv(ac2ptr)->timestamp >
469 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
472 if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
474 /* If timestamps are equal, decide which link to break
477 if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
478 (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
486 n2 = cli_name(c2ptr);
487 n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
492 n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
496 n3 = cli_name(c3ptr);
497 n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
502 n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
504 if (strcmp(n2, n2up) > 0)
506 if (strcmp(n3, n3up) > 0)
508 if (strcmp(n3, n2) > 0)
515 /* Now squit the second youngest link: */
517 return exit_new_server(cptr, sptr, host, timestamp,
518 "server %s already exists and is %ld seconds younger.",
519 host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
520 else if (cli_from(c2ptr) == cptr || IsServer(sptr))
522 struct Client *killedptrfrom = cli_from(c2ptr);
526 * If the L: or H: line also gets rid of this link,
527 * we sent just one squit.
529 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
532 * If breaking the loop here solves the L: or H:
533 * line problem, we don't squit that.
535 if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
540 * If we still have a L: or H: line problem,
541 * we prefer to squit the new server, solving
542 * loop and L:/H: line problem with only one squit.
549 * If the new server was introduced by a server that caused a
550 * Ghost less then 20 seconds ago, this is probably also
551 * a Ghost... (20 seconds is more then enough because all
552 * SERVER messages are at the beginning of a net.burst). --Run
554 if (CurrentTime - cli_serv(cptr)->ghost < 20)
556 killedptrfrom = cli_from(acptr);
557 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
560 else if (exit_client_msg(cptr, c2ptr, &me,
561 "Loop <-- %s (new link is %ld seconds younger)", host,
562 (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
563 (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
566 * Did we kill the incoming server off already ?
568 if (killedptrfrom == cptr)
575 if (LHcptr && a_kills_b_too(LHcptr, acptr))
577 if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
586 * We can't believe it is a lagged server message
587 * when it directly connects to us...
588 * kill the older link at the ghost, rather then
589 * at the second youngest link, assuming it isn't
592 ghost = CurrentTime; /* Mark that it caused a ghost */
593 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
603 return exit_new_server(cptr, sptr, host, timestamp,
604 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
605 "Leaf-only link %s <- %s(%s), check L:",
606 cli_name(cptr), host,
607 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
611 int killed = a_kills_b_too(LHcptr, sptr);
612 if (active_lh_line < 3)
614 if (exit_client_msg(cptr, LHcptr, &me,
615 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
616 "Leaf-only link %s <- %s(%s), check L:",
617 cli_name(cptr), host,
618 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
623 ServerStats->is_ref++;
624 if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
628 * Did we kill the incoming server off already ?
638 * Server is informing about a new server behind
639 * this link. Create REMOTE server structure,
640 * add it to list and propagate word to my other
644 acptr = make_client(cptr, STAT_SERVER);
646 cli_serv(acptr)->prot = prot;
647 cli_serv(acptr)->timestamp = timestamp;
648 cli_hopcount(acptr) = hop;
649 ircd_strncpy(cli_name(acptr), host, HOSTLEN);
650 ircd_strncpy(cli_info(acptr), info, REALLEN);
651 cli_serv(acptr)->up = sptr;
652 cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
653 /* Use cptr, because we do protocol 9 -> 10 translation
654 for numeric nicks ! */
655 SetServerYXX(cptr, acptr, parv[6]);
657 Count_newremoteserver(UserStats);
658 if (Protocol(acptr) < 10)
659 cli_flags(acptr) |= FLAGS_TS8;
660 add_client_to_list(acptr);
665 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
666 cli_name(sptr), cli_name(acptr));
670 * Old sendto_serv_but_one() call removed because we now need to send
671 * different names to different servers (domain name matching).
673 * Personally, I think this is bogus; it's a feature we don't use here.
676 for (i = 0; i <= HighestFd; i++)
678 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
679 bcptr == cptr || IsMe(bcptr))
681 if (0 == match(cli_name(&me), cli_name(acptr)))
683 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
684 cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
690 if (IsUnknown(cptr) || IsHandshake(cptr))
693 cli_serv(cptr)->timestamp = timestamp;
694 cli_serv(cptr)->prot = prot;
695 cli_serv(cptr)->ghost = ghost;
696 SetServerYXX(cptr, cptr, parv[6]);
697 if (start_timestamp > OLDEST_TS)
699 Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
700 cli_serv(&me)->timestamp, start_timestamp));
701 Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
702 "difference %ld", recv_time, timestamp, timestamp - recv_time));
703 if (feature_bool(FEAT_RELIABLE_CLOCK)) {
704 if (start_timestamp < cli_serv(&me)->timestamp)
705 cli_serv(&me)->timestamp = start_timestamp;
707 cli_serv(cptr)->timestamp = TStime();
709 if (start_timestamp < cli_serv(&me)->timestamp) {
710 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
711 "%Tu < %Tu", start_timestamp,
712 cli_serv(&me)->timestamp);
713 cli_serv(&me)->timestamp = start_timestamp;
714 TSoffset += timestamp - recv_time;
715 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
716 (int)(timestamp - recv_time));
717 } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
719 cli_serv(cptr)->timestamp = TStime();
721 else if (timestamp != recv_time) {
723 * Equal start times, we have a collision. Let the connected-to
724 * server decide. This assumes leafs issue more than half of the
725 * connection attempts.
728 cli_serv(cptr)->timestamp = TStime();
729 else if (IsHandshake(cptr)) {
730 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
731 (int)(timestamp - recv_time));
732 TSoffset += timestamp - recv_time;
738 ret = server_estab(cptr, aconf, ajupe);
743 if (feature_bool(FEAT_RELIABLE_CLOCK) &&
744 abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
745 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
746 "timestamp-clock difference of %Td seconds! "
747 "Used SETTIME to correct this.",
748 timestamp - recv_time);
749 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
756 * ms_server - server message handler
758 * parv[0] = sender prefix
759 * parv[1] = servername
761 * parv[3] = start timestamp
762 * parv[4] = link timestamp
763 * parv[5] = major protocol version: P09/P10
764 * parv[parc-1] = serverinfo
766 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
767 * numeric nick mask of this server.
768 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
769 * parv[8] = %<lastmod> - optional parameter only present if there's an
770 * outstanding JUPE; specifies the JUPE's lastmod field
772 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
776 char info[REALLEN + 1];
778 struct Client* acptr;
779 struct Client* bcptr;
780 struct Client* LHcptr = 0;
781 struct ConfItem* aconf = 0;
782 struct ConfItem* lhconf = 0;
783 struct Jupe* ajupe = 0;
786 int active_lh_line = 0;
788 time_t start_timestamp;
789 time_t timestamp = 0;
794 if (IsUserPort(cptr))
795 return exit_client_msg(cptr, cptr, &me,
796 "Cannot connect a server to a user port");
798 recv_time = TStime();
802 return need_more_params(sptr, "SERVER");
803 return exit_client(cptr, cptr, &me, "Need more parameters");
810 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
811 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
813 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
816 prot = atoi(parv[5] + 1);
817 if (prot > atoi(MAJOR_PROTOCOL))
818 prot = atoi(MAJOR_PROTOCOL);
820 * Because the previous test is only in 2.10, the following is needed
821 * till all servers are 2.10:
823 if (IsServer(cptr) && prot > Protocol(cptr))
824 prot = Protocol(cptr);
826 start_timestamp = atoi(parv[3]);
827 timestamp = atoi(parv[4]);
828 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
829 host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
830 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
832 return exit_client_msg(cptr, sptr, &me,
833 "Bogus timestamps (%s %s)", parv[3], parv[4]);
835 ircd_strncpy(info, parv[parc - 1], REALLEN);
836 info[REALLEN] = '\0';
837 if (prot < atoi(MINOR_PROTOCOL)) {
838 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
839 "(%s) from %s", parv[5], cli_name(cptr));
840 return exit_new_server(cptr, sptr, host, timestamp,
841 "Incompatible protocol: %s", parv[5]);
843 if (parc > 9 && *parv[8] == '%')
844 lastmod = atoi(parv[8] + 1);
845 /* If there's a jupe that matches, and it's a global jupe, and the
846 * introducer didn't indicate it knew of the jupe or has an older
847 * version of the jupe, and the connection isn't in a BURST, resynch
850 if ((ajupe = jupe_find(host)) && !JupeIsLocal(ajupe) &&
851 JupeLastMod(ajupe) > lastmod && !IsBurstOrBurstAck(cptr))
852 jupe_resend(cptr, ajupe);
854 * Check for "FRENCH " infection ;-) (actually this should
855 * be replaced with routine to check the hostname syntax in
856 * general). [ This check is still needed, even after the parse
857 * is fixed, because someone can send "SERVER :foo bar " ].
858 * Also, changed to check other "difficult" characters, now
859 * that parse lets all through... --msa
861 if (strlen(host) > HOSTLEN)
862 host[HOSTLEN] = '\0';
863 for (ch = host; *ch; ch++)
864 if (*ch <= ' ' || *ch > '~')
866 if (*ch || !strchr(host, '.')) {
867 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
868 host, cli_name(cptr));
869 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
875 * A local server introduces a new server behind this link.
876 * Check if this is allowed according L:, H: and Q: lines.
879 return exit_client_msg(cptr, cptr, &me,
880 "No server info specified for %s", host);
882 * See if the newly found server is behind a guaranteed
883 * leaf (L-line). If so, close the link.
885 if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
886 (!lhconf->port || (hop > lhconf->port)))
889 * L: lines normally come in pairs, here we try to
890 * make sure that the oldest link is squitted, not
894 if (timestamp <= cli_serv(cptr)->timestamp)
895 LHcptr = 0; /* Kill incoming server */
897 LHcptr = cptr; /* Squit ourselfs */
899 else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
900 (lhconf->port && (hop > lhconf->port)))
902 struct Client *ac3ptr;
904 /* Look for net junction causing this: */
905 LHcptr = 0; /* incoming server */
906 if (*parv[5] != 'J') {
907 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
908 if (IsJunction(ac3ptr)) {
917 if (IsUnknown(cptr) || IsHandshake(cptr))
922 * A local link that is still in undefined state wants
923 * to be a SERVER. Check if this is allowed and change
924 * status accordingly...
927 * If there is more then one server on the same machine
928 * that we try to connect to, it could be that the /CONNECT
929 * <mask> caused this connect to be put at the wrong place
930 * in the hashtable. --Run
931 * Same thing for Unknown connections that first send NICK.
933 * Better check if the two strings are (caseless) identical
934 * and not mess with hash internals.
937 if ((!(EmptyString(cli_name(cptr))))
938 && (IsUnknown(cptr) || IsHandshake(cptr))
939 && 0 != ircd_strcmp(cli_name(cptr), host))
940 hChangeClient(cptr, host);
941 ircd_strncpy(cli_name(cptr), host, HOSTLEN);
942 ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
943 cli_hopcount(cptr) = hop;
945 /* check connection rules */
946 if (0 != conf_eval_crule(host, CRULE_ALL)) {
947 ServerStats->is_ref++;
948 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
949 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
951 if (conf_check_server(cptr)) {
952 ++ServerStats->is_ref;
953 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
954 "from %s.", cli_name(cptr));
955 return exit_client(cptr, cptr, &me, "No C conf lines");
958 host = cli_name(cptr);
962 if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
963 ++ServerStats->is_ref;
964 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
965 "server %s", cli_name(cptr));
966 return exit_client_msg(cptr, cptr, &me,
967 "Access denied. No conf line for server %s", cli_name(cptr));
969 encr = cli_passwd(cptr);
971 if (*(aconf->passwd) && !!strcmp(aconf->passwd, encr)) {
972 ++ServerStats->is_ref;
973 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
975 return exit_client_msg(cptr, cptr, &me,
976 "No Access (passwd mismatch) %s", cli_name(cptr));
978 memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
980 if (!feature_bool(FEAT_HUB)) {
981 for (i = 0; i <= HighestFd; i++)
982 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
991 * We want to find IsConnecting() and IsHandshake() too,
993 * The second finds collisions with numeric representation of existing
994 * servers - these shouldn't happen anymore when all upgraded to 2.10.
997 while ((acptr = FindClient(host)) ||
998 (parc > 7 && (acptr = FindNServer(parv[6]))))
1001 * This link is trying feed me a server that I already have
1002 * access through another path
1004 * Do not allow Uworld to do this.
1005 * Do not allow servers that are juped.
1006 * Do not allow servers that have older link timestamps
1008 * Do not allow servers that use the same numeric as an existing
1009 * server, but have a different name.
1011 * If my ircd.conf sucks, I can try to connect to myself:
1014 return exit_client_msg(cptr, cptr, &me,
1015 "nick collision with me, check server number in M:? (%s)", host);
1017 * Detect wrong numeric.
1019 if (0 != ircd_strcmp(cli_name(acptr), host))
1021 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1022 ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
1024 return exit_client_msg(cptr, cptr, &me,
1025 "NUMERIC collision between %s and %s."
1026 " Is your server numeric correct ?", host, cli_name(acptr));
1029 * Kill our try, if we had one.
1031 if (IsConnecting(acptr))
1033 if (!active_lh_line && exit_client(cptr, acptr, &me,
1034 "Just connected via another link") == CPTR_KILLED)
1037 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1038 * 'IsServer', because new 'IsConnecting's are refused to
1039 * the same server if we already had it.
1044 * Avoid other nick collisions...
1045 * This is a doubtfull test though, what else would it be
1046 * when it has a server.name ?
1048 else if (!IsServer(acptr) && !IsHandshake(acptr))
1049 return exit_client_msg(cptr, cptr, &me,
1050 "Nickname %s already exists!", host);
1052 * Our new server might be a juped server,
1053 * or someone trying abuse a second Uworld:
1055 else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
1056 find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
1058 if (!IsServer(sptr))
1059 return exit_client(cptr, sptr, &me, cli_info(acptr));
1060 sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1061 "from %s !?!", parv[0], parv[1], cli_name(cptr));
1062 return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
1065 * Of course we find the handshake this link was before :)
1067 else if (IsHandshake(acptr) && acptr == cptr)
1070 * Here we have a server nick collision...
1071 * We don't want to kill the link that was last /connected,
1072 * but we neither want to kill a good (old) link.
1073 * Therefor we kill the second youngest link.
1077 struct Client* c2ptr = 0;
1078 struct Client* c3ptr = acptr;
1079 struct Client* ac2ptr;
1080 struct Client* ac3ptr;
1082 /* Search youngest link: */
1083 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1084 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1088 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1089 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1092 if (timestamp > cli_serv(c3ptr)->timestamp)
1095 c2ptr = acptr; /* Make sure they differ */
1097 /* Search second youngest link: */
1098 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1099 if (ac2ptr != c3ptr &&
1100 cli_serv(ac2ptr)->timestamp >
1101 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1105 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1106 if (ac2ptr != c3ptr &&
1107 cli_serv(ac2ptr)->timestamp >
1108 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1111 if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1113 /* If timestamps are equal, decide which link to break
1116 if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
1117 (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
1125 n2 = cli_name(c2ptr);
1126 n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
1131 n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1135 n3 = cli_name(c3ptr);
1136 n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
1141 n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1143 if (strcmp(n2, n2up) > 0)
1145 if (strcmp(n3, n3up) > 0)
1147 if (strcmp(n3, n2) > 0)
1154 /* Now squit the second youngest link: */
1156 return exit_new_server(cptr, sptr, host, timestamp,
1157 "server %s already exists and is %ld seconds younger.",
1158 host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
1159 else if (cli_from(c2ptr) == cptr || IsServer(sptr))
1161 struct Client *killedptrfrom = cli_from(c2ptr);
1165 * If the L: or H: line also gets rid of this link,
1166 * we sent just one squit.
1168 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1171 * If breaking the loop here solves the L: or H:
1172 * line problem, we don't squit that.
1174 if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1179 * If we still have a L: or H: line problem,
1180 * we prefer to squit the new server, solving
1181 * loop and L:/H: line problem with only one squit.
1188 * If the new server was introduced by a server that caused a
1189 * Ghost less then 20 seconds ago, this is probably also
1190 * a Ghost... (20 seconds is more then enough because all
1191 * SERVER messages are at the beginning of a net.burst). --Run
1193 if (CurrentTime - cli_serv(cptr)->ghost < 20)
1195 killedptrfrom = cli_from(acptr);
1196 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1199 else if (exit_client_msg(cptr, c2ptr, &me,
1200 "Loop <-- %s (new link is %ld seconds younger)", host,
1201 (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
1202 (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
1205 * Did we kill the incoming server off already ?
1207 if (killedptrfrom == cptr)
1214 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1216 if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1225 * We can't believe it is a lagged server message
1226 * when it directly connects to us...
1227 * kill the older link at the ghost, rather then
1228 * at the second youngest link, assuming it isn't
1231 ghost = CurrentTime; /* Mark that it caused a ghost */
1232 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1242 return exit_new_server(cptr, sptr, host, timestamp,
1243 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1244 cli_name(cptr), host,
1245 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1249 int killed = a_kills_b_too(LHcptr, sptr);
1250 if (active_lh_line < 3)
1252 if (exit_client_msg(cptr, LHcptr, &me,
1253 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1254 cli_name(cptr), host,
1255 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1260 ServerStats->is_ref++;
1261 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1265 * Did we kill the incoming server off already ?
1275 * Server is informing about a new server behind
1276 * this link. Create REMOTE server structure,
1277 * add it to list and propagate word to my other
1281 acptr = make_client(cptr, STAT_SERVER);
1283 cli_serv(acptr)->prot = prot;
1284 cli_serv(acptr)->timestamp = timestamp;
1285 cli_hopcount(acptr) = hop;
1286 ircd_strncpy(cli_name(acptr), host, HOSTLEN);
1287 ircd_strncpy(cli_info(acptr), info, REALLEN);
1288 cli_serv(acptr)->up = sptr;
1289 cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
1290 /* Use cptr, because we do protocol 9 -> 10 translation
1291 for numeric nicks ! */
1292 SetServerYXX(cptr, acptr, parv[6]);
1294 Count_newremoteserver(UserStats);
1295 if (Protocol(acptr) < 10)
1296 cli_flags(acptr) |= FLAGS_TS8;
1297 add_client_to_list(acptr);
1299 if (*parv[5] == 'J')
1302 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1303 cli_name(sptr), cli_name(acptr));
1307 * Old sendto_serv_but_one() call removed because we now need to send
1308 * different names to different servers (domain name matching).
1310 for (i = 0; i <= HighestFd; i++)
1312 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1313 bcptr == cptr || IsMe(bcptr))
1315 if (0 == match(cli_name(&me), cli_name(acptr)))
1317 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1318 cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
1324 if (IsUnknown(cptr) || IsHandshake(cptr))
1327 cli_serv(cptr)->timestamp = timestamp;
1328 cli_serv(cptr)->prot = prot;
1329 cli_serv(cptr)->ghost = ghost;
1330 SetServerYXX(cptr, cptr, parv[6]);
1331 if (start_timestamp > OLDEST_TS)
1333 Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
1334 cli_serv(&me)->timestamp, start_timestamp));
1335 Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
1336 "difference %ld", recv_time, timestamp, timestamp - recv_time));
1337 if (feature_bool(FEAT_RELIABLE_CLOCK)) {
1338 if (start_timestamp < cli_serv(&me)->timestamp)
1339 cli_serv(&me)->timestamp = start_timestamp;
1340 if (IsUnknown(cptr))
1341 cli_serv(cptr)->timestamp = TStime();
1343 if (start_timestamp < cli_serv(&me)->timestamp) {
1344 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1345 "%Tu < %Tu", start_timestamp,
1346 cli_serv(&me)->timestamp);
1347 cli_serv(&me)->timestamp = start_timestamp;
1348 TSoffset += timestamp - recv_time;
1349 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1350 (int)(timestamp - recv_time));
1351 } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
1353 cli_serv(cptr)->timestamp = TStime();
1355 else if (timestamp != recv_time) {
1357 * Equal start times, we have a collision. Let the connected-to
1358 * server decide. This assumes leafs issue more than half of the
1359 * connection attempts.
1361 if (IsUnknown(cptr))
1362 cli_serv(cptr)->timestamp = TStime();
1363 else if (IsHandshake(cptr)) {
1364 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1365 (int)(timestamp - recv_time));
1366 TSoffset += timestamp - recv_time;
1372 ret = server_estab(cptr, aconf, ajupe);
1377 if (feature_bool(FEAT_RELIABLE_CLOCK) &&
1378 abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
1379 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1380 "timestamp-clock difference of %Td seconds! Used "
1381 "SETTIME to correct this.", timestamp - recv_time);
1382 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
1393 * parv[0] = sender prefix
1394 * parv[1] = servername
1395 * parv[2] = hopcount
1396 * parv[3] = start timestamp
1397 * parv[4] = link timestamp
1398 * parv[5] = major protocol version: P09/P10
1399 * parv[parc-1] = serverinfo
1401 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1402 * numeric nick mask of this server.
1403 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1405 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1409 char info[REALLEN + 1];
1411 struct Client* acptr;
1412 struct Client* bcptr;
1413 struct Client* LHcptr = 0;
1414 struct ConfItem* aconf = 0;
1415 struct ConfItem* lhconf = 0;
1416 struct Jupe* ajupe = 0;
1419 int active_lh_line = 0;
1420 unsigned short prot;
1421 time_t start_timestamp;
1422 time_t timestamp = 0;
1428 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1432 if (IsUserPort(cptr))
1433 return exit_client_msg(cptr, cptr, &me,
1434 "You cannot connect a server to a user port; connect to %s port %u",
1435 me.name, server_port);
1437 recv_time = TStime();
1441 return need_more_params(sptr, "SERVER");
1442 return exit_client(cptr, cptr, &me, "Need more parameters");
1448 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1449 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1451 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1454 prot = atoi(parv[5] + 1);
1455 if (prot > atoi(MAJOR_PROTOCOL))
1456 prot = atoi(MAJOR_PROTOCOL);
1458 * Because the previous test is only in 2.10, the following is needed
1459 * till all servers are 2.10:
1461 if (IsServer(cptr) && prot > Protocol(cptr))
1462 prot = Protocol(cptr);
1463 hop = atoi(parv[2]);
1464 start_timestamp = atoi(parv[3]);
1465 timestamp = atoi(parv[4]);
1466 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1467 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1468 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1470 return exit_client_msg(cptr, sptr, &me,
1471 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1473 ircd_strncpy(info, parv[parc - 1], REALLEN);
1474 info[REALLEN] = '\0';
1475 if (prot < atoi(MINOR_PROTOCOL)) {
1476 sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1477 parv[5], cptr->name);
1478 return exit_new_server(cptr, sptr, host, timestamp,
1479 "Incompatible protocol: %s", parv[5]);
1482 * Check for "FRENCH " infection ;-) (actually this should
1483 * be replaced with routine to check the hostname syntax in
1484 * general). [ This check is still needed, even after the parse
1485 * is fixed, because someone can send "SERVER :foo bar " ].
1486 * Also, changed to check other "difficult" characters, now
1487 * that parse lets all through... --msa
1489 if (strlen(host) > HOSTLEN)
1490 host[HOSTLEN] = '\0';
1491 for (ch = host; *ch; ch++)
1492 if (*ch <= ' ' || *ch > '~')
1494 if (*ch || !strchr(host, '.'))
1496 sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1497 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1503 * A local server introduces a new server behind this link.
1504 * Check if this is allowed according L:, H: and Q: lines.
1506 if (info[0] == '\0')
1507 return exit_client_msg(cptr, cptr, &me,
1508 "No server info specified for %s", host);
1510 * See if the newly found server is behind a guaranteed
1511 * leaf (L-line). If so, close the link.
1513 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1514 (!lhconf->port || (hop > lhconf->port)))
1517 * L: lines normally come in pairs, here we try to
1518 * make sure that the oldest link is squitted, not
1522 if (timestamp <= cptr->serv->timestamp)
1523 LHcptr = 0; /* Kill incoming server */
1525 LHcptr = cptr; /* Squit ourselfs */
1527 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1528 (lhconf->port && (hop > lhconf->port)))
1530 struct Client *ac3ptr;
1532 /* Look for net junction causing this: */
1533 LHcptr = 0; /* incoming server */
1534 if (*parv[5] != 'J') {
1535 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1536 if (IsJunction(ac3ptr)) {
1545 if (IsUnknown(cptr) || IsHandshake(cptr))
1550 * A local link that is still in undefined state wants
1551 * to be a SERVER. Check if this is allowed and change
1552 * status accordingly...
1555 * If there is more then one server on the same machine
1556 * that we try to connect to, it could be that the /CONNECT
1557 * <mask> caused this connect to be put at the wrong place
1558 * in the hashtable. --Run
1559 * Same thing for Unknown connections that first send NICK.
1561 * Better check if the two strings are (caseless) identical
1562 * and not mess with hash internals.
1565 if ((!(EmptyString(cptr->name)))
1566 && (IsUnknown(cptr) || IsHandshake(cptr))
1567 && 0 != ircd_strcmp(cptr->name, host))
1568 hChangeClient(cptr, host);
1569 ircd_strncpy(cptr->name, host, HOSTLEN);
1570 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1571 cptr->hopcount = hop;
1573 /* check connection rules */
1574 if (0 != conf_eval_crule(host, CRULE_ALL)) {
1575 ServerStats->is_ref++;
1576 sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1577 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1579 if (conf_check_server(cptr)) {
1580 ++ServerStats->is_ref;
1581 sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1582 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1589 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1590 ++ServerStats->is_ref;
1592 sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1593 return exit_client_msg(cptr, cptr, &me,
1594 "Access denied. No conf line for server %s", cptr->name);
1596 sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1598 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1600 sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1601 "\"general.undernet.org\"", cptr->name);
1602 return exit_client_msg(cptr, cptr, &me,
1603 "No C/N lines for server %s", cptr->name);
1605 #endif /* GODMODE */
1607 #ifdef CRYPT_LINK_PASSWORD
1608 /* passwd may be NULL. Head it off at the pass... */
1611 encr = ircd_crypt(cptr->passwd, aconf->passwd);
1616 encr = cptr->passwd;
1617 #endif /* CRYPT_LINK_PASSWORD */
1619 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1620 ++ServerStats->is_ref;
1621 sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1622 return exit_client_msg(cptr, cptr, &me,
1623 "No Access (passwd mismatch) %s", cptr->name);
1625 #endif /* not GODMODE */
1626 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1629 for (i = 0; i <= HighestFd; i++)
1630 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1639 * We want to find IsConnecting() and IsHandshake() too,
1641 * The second finds collisions with numeric representation of existing
1642 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1645 while ((acptr = FindClient(host)) ||
1646 (parc > 7 && (acptr = FindNServer(parv[6]))))
1649 * This link is trying feed me a server that I already have
1650 * access through another path
1652 * Do not allow Uworld to do this.
1653 * Do not allow servers that are juped.
1654 * Do not allow servers that have older link timestamps
1656 * Do not allow servers that use the same numeric as an existing
1657 * server, but have a different name.
1659 * If my ircd.conf sucks, I can try to connect to myself:
1662 return exit_client_msg(cptr, cptr, &me,
1663 "nick collision with me, check server number in M:? (%s)", host);
1665 * Detect wrong numeric.
1667 if (0 != ircd_strcmp(acptr->name, host))
1669 sendto_serv_butone(cptr, /* XXX DEAD */
1670 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1671 me.name, acptr->name, host);
1672 return exit_client_msg(cptr, cptr, &me,
1673 "NUMERIC collision between %s and %s."
1674 " Is your server numeric correct ?", host, acptr->name);
1677 * Kill our try, if we had one.
1679 if (IsConnecting(acptr))
1681 if (!active_lh_line && exit_client(cptr, acptr, &me,
1682 "Just connected via another link") == CPTR_KILLED)
1685 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1686 * 'IsServer', because new 'IsConnecting's are refused to
1687 * the same server if we already had it.
1692 * Avoid other nick collisions...
1693 * This is a doubtfull test though, what else would it be
1694 * when it has a server.name ?
1696 else if (!IsServer(acptr) && !IsHandshake(acptr))
1697 return exit_client_msg(cptr, cptr, &me,
1698 "Nickname %s already exists!", host);
1700 * Our new server might be a juped server,
1701 * or someone trying abuse a second Uworld:
1703 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1704 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1706 if (!IsServer(sptr))
1707 return exit_client(cptr, sptr, &me, acptr->info);
1708 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1709 me.name, parv[0], parv[1], cptr->name);
1710 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1713 * Of course we find the handshake this link was before :)
1715 else if (IsHandshake(acptr) && acptr == cptr)
1718 * Here we have a server nick collision...
1719 * We don't want to kill the link that was last /connected,
1720 * but we neither want to kill a good (old) link.
1721 * Therefor we kill the second youngest link.
1725 struct Client* c2ptr = 0;
1726 struct Client* c3ptr = acptr;
1727 struct Client* ac2ptr;
1728 struct Client* ac3ptr;
1730 /* Search youngest link: */
1731 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1732 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1736 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1737 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1740 if (timestamp > c3ptr->serv->timestamp)
1743 c2ptr = acptr; /* Make sure they differ */
1745 /* Search second youngest link: */
1746 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1747 if (ac2ptr != c3ptr &&
1748 ac2ptr->serv->timestamp >
1749 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1753 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1754 if (ac2ptr != c3ptr &&
1755 ac2ptr->serv->timestamp >
1756 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1759 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1761 /* If timestamps are equal, decide which link to break
1764 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1765 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1774 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1779 n2up = IsServer(sptr) ? sptr->name : me.name;
1784 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1789 n3up = IsServer(sptr) ? sptr->name : me.name;
1791 if (strcmp(n2, n2up) > 0)
1793 if (strcmp(n3, n3up) > 0)
1795 if (strcmp(n3, n2) > 0)
1802 /* Now squit the second youngest link: */
1804 return exit_new_server(cptr, sptr, host, timestamp,
1805 "server %s already exists and is %ld seconds younger.",
1806 host, (long)acptr->serv->timestamp - (long)timestamp);
1807 else if (c2ptr->from == cptr || IsServer(sptr))
1809 struct Client *killedptrfrom = c2ptr->from;
1813 * If the L: or H: line also gets rid of this link,
1814 * we sent just one squit.
1816 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1819 * If breaking the loop here solves the L: or H:
1820 * line problem, we don't squit that.
1822 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1827 * If we still have a L: or H: line problem,
1828 * we prefer to squit the new server, solving
1829 * loop and L:/H: line problem with only one squit.
1836 * If the new server was introduced by a server that caused a
1837 * Ghost less then 20 seconds ago, this is probably also
1838 * a Ghost... (20 seconds is more then enough because all
1839 * SERVER messages are at the beginning of a net.burst). --Run
1841 if (CurrentTime - cptr->serv->ghost < 20)
1843 killedptrfrom = acptr->from;
1844 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1847 else if (exit_client_msg(cptr, c2ptr, &me,
1848 "Loop <-- %s (new link is %ld seconds younger)", host,
1849 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1850 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1853 * Did we kill the incoming server off already ?
1855 if (killedptrfrom == cptr)
1862 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1864 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1873 * We can't believe it is a lagged server message
1874 * when it directly connects to us...
1875 * kill the older link at the ghost, rather then
1876 * at the second youngest link, assuming it isn't
1879 ghost = CurrentTime; /* Mark that it caused a ghost */
1880 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1890 return exit_new_server(cptr, sptr, host, timestamp,
1891 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1893 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1897 int killed = a_kills_b_too(LHcptr, sptr);
1898 if (active_lh_line < 3)
1900 if (exit_client_msg(cptr, LHcptr, &me,
1901 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1903 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1908 ServerStats->is_ref++;
1909 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1913 * Did we kill the incoming server off already ?
1923 * Server is informing about a new server behind
1924 * this link. Create REMOTE server structure,
1925 * add it to list and propagate word to my other
1929 acptr = make_client(cptr, STAT_SERVER);
1931 acptr->serv->prot = prot;
1932 acptr->serv->timestamp = timestamp;
1933 acptr->hopcount = hop;
1934 ircd_strncpy(acptr->name, host, HOSTLEN);
1935 ircd_strncpy(acptr->info, info, REALLEN);
1936 acptr->serv->up = sptr;
1937 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1938 /* Use cptr, because we do protocol 9 -> 10 translation
1939 for numeric nicks ! */
1940 SetServerYXX(cptr, acptr, parv[6]);
1942 Count_newremoteserver(UserStats);
1943 if (Protocol(acptr) < 10)
1944 acptr->flags |= FLAGS_TS8;
1945 add_client_to_list(acptr);
1947 if (*parv[5] == 'J')
1950 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
1951 sptr->name, acptr->name);
1955 * Old sendto_serv_but_one() call removed because we now need to send
1956 * different names to different servers (domain name matching).
1958 for (i = 0; i <= HighestFd; i++)
1960 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1961 bcptr == cptr || IsMe(bcptr))
1963 if (0 == match(me.name, acptr->name))
1965 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
1966 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1967 NumServCap(acptr), acptr->info);
1972 if (IsUnknown(cptr) || IsHandshake(cptr))
1975 cptr->serv->timestamp = timestamp;
1976 cptr->serv->prot = prot;
1977 cptr->serv->ghost = ghost;
1978 SetServerYXX(cptr, cptr, parv[6]);
1979 if (start_timestamp > OLDEST_TS)
1981 #ifndef RELIABLE_CLOCK
1983 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
1984 TIME_T_FMT, me.serv->timestamp, start_timestamp);
1985 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
1986 TIME_T_FMT " ; difference %ld",
1987 recv_time, timestamp, timestamp - recv_time);
1989 if (start_timestamp < me.serv->timestamp)
1991 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
1992 start_timestamp, me.serv->timestamp);
1993 me.serv->timestamp = start_timestamp;
1994 TSoffset += timestamp - recv_time;
1995 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
1997 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1998 cptr->serv->timestamp = TStime();
2000 else if (timestamp != recv_time)
2003 * Equal start times, we have a collision. Let the connected-to server
2004 * decide. This assumes leafs issue more than half of the connection
2007 if (IsUnknown(cptr))
2008 cptr->serv->timestamp = TStime();
2009 else if (IsHandshake(cptr))
2011 sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
2012 (int)(timestamp - recv_time));
2013 TSoffset += timestamp - recv_time;
2016 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2017 if (start_timestamp < me.serv->timestamp)
2018 me.serv->timestamp = start_timestamp;
2019 if (IsUnknown(cptr))
2020 cptr->serv->timestamp = TStime();
2024 ret = server_estab(cptr, aconf); /* XXX DEAD */
2028 #ifdef RELIABLE_CLOCK
2029 if (abs(cptr->serv->timestamp - recv_time) > 30)
2031 sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2032 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2033 " this.", timestamp - recv_time);
2034 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2035 me.name, TStime(), me.name);