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
84 * No need to include handlers.h here the signatures must match
85 * and we don't need to force a rebuild of all the handlers everytime
86 * we add a new one to the list. --Bleep
94 #include "ircd_features.h"
95 #include "ircd_reply.h"
96 #include "ircd_string.h"
102 #include "numnicks.h"
103 #include "querycmds.h"
110 #include "userload.h"
117 * mr_server - registration message handler
119 * parv[0] = sender prefix
120 * parv[1] = servername
122 * parv[3] = start timestamp
123 * parv[4] = link timestamp
124 * parv[5] = major protocol version: P09/P10
125 * parv[parc-1] = serverinfo
127 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
128 * numeric nick mask of this server.
129 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
131 int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
135 char info[REALLEN + 1];
137 struct Client* acptr;
138 struct Client* bcptr;
139 struct Client* LHcptr = 0;
140 struct ConfItem* aconf = 0;
141 struct ConfItem* lhconf = 0;
142 struct Jupe* ajupe = 0;
145 int active_lh_line = 0;
147 time_t start_timestamp;
148 time_t timestamp = 0;
152 if (IsUserPort(cptr))
153 return exit_client_msg(cptr, cptr, &me,
154 "Cannot connect a server to a user port");
156 recv_time = TStime();
161 need_more_params(sptr, "SERVER");
162 return exit_client(cptr, cptr, &me, "Need more parameters");
166 if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
167 return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
169 log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "SERVER: %s %s[%s]", parv[1],
170 cli_sockhost(cptr), cli_sock_ip(cptr));
175 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
176 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
178 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
181 prot = atoi(parv[5] + 1);
182 if (prot > atoi(MAJOR_PROTOCOL))
183 prot = atoi(MAJOR_PROTOCOL);
185 * Because the previous test is only in 2.10, the following is needed
186 * till all servers are 2.10:
188 if (IsServer(cptr) && prot > Protocol(cptr))
189 prot = Protocol(cptr);
191 start_timestamp = atoi(parv[3]);
192 timestamp = atoi(parv[4]);
193 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
194 TIME_T_FMT ")", host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
196 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
198 return exit_client_msg(cptr, sptr, &me,
199 "Bogus timestamps (%s %s)", parv[3], parv[4]);
201 ircd_strncpy(info, parv[parc - 1], REALLEN);
202 info[REALLEN] = '\0';
203 if (prot < atoi(MINOR_PROTOCOL)) {
204 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
205 "(%s) from %s", parv[5], cli_name(cptr));
206 return exit_new_server(cptr, sptr, host, timestamp,
207 "Incompatible protocol: %s", parv[5]);
210 * Check for "FRENCH " infection ;-) (actually this should
211 * be replaced with routine to check the hostname syntax in
212 * general). [ This check is still needed, even after the parse
213 * is fixed, because someone can send "SERVER :foo bar " ].
214 * Also, changed to check other "difficult" characters, now
215 * that parse lets all through... --msa
217 if (strlen(host) > HOSTLEN)
218 host[HOSTLEN] = '\0';
220 for (ch = host; *ch; ch++) {
221 if (*ch <= ' ' || *ch > '~')
224 if (*ch || !strchr(host, '.')) {
225 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
226 host, cli_name(cptr));
227 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
233 * A local server introduces a new server behind this link.
234 * Check if this is allowed according L:, H: and Q: lines.
237 return exit_client_msg(cptr, cptr, &me,
238 "No server info specified for %s", host);
240 * See if the newly found server is behind a guaranteed
241 * leaf (L-line). If so, close the link.
243 if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
244 (!lhconf->port || (hop > lhconf->port)))
247 * L: lines normally come in pairs, here we try to
248 * make sure that the oldest link is squitted, not
252 if (timestamp <= cli_serv(cptr)->timestamp)
253 LHcptr = 0; /* Kill incoming server */
255 LHcptr = cptr; /* Squit ourselfs */
257 else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
258 (lhconf->port && (hop > lhconf->port)))
260 struct Client *ac3ptr;
262 /* Look for net junction causing this: */
263 LHcptr = 0; /* incoming server */
264 if (*parv[5] != 'J') {
265 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
266 if (IsJunction(ac3ptr)) {
275 if (IsUnknown(cptr) || IsHandshake(cptr))
280 * A local link that is still in undefined state wants
281 * to be a SERVER. Check if this is allowed and change
282 * status accordingly...
285 * If there is more then one server on the same machine
286 * that we try to connect to, it could be that the /CONNECT
287 * <mask> caused this connect to be put at the wrong place
288 * in the hashtable. --Run
289 * Same thing for Unknown connections that first send NICK.
291 * Better check if the two strings are (caseless) identical
292 * and not mess with hash internals.
295 if (!EmptyString(cli_name(cptr)) &&
296 (IsUnknown(cptr) || IsHandshake(cptr)) &&
297 0 != ircd_strcmp(cli_name(cptr), host))
298 hChangeClient(cptr, host);
299 ircd_strncpy(cli_name(cptr), host, HOSTLEN);
300 ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
301 cli_hopcount(cptr) = hop;
303 /* check connection rules */
304 if (0 != conf_eval_crule(host, CRULE_ALL)) {
305 ServerStats->is_ref++;
306 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
307 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
310 if (conf_check_server(cptr)) {
311 ++ServerStats->is_ref;
312 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
313 "from %s.", cli_name(cptr));
314 return exit_client(cptr, cptr, &me, "No C:line");
317 host = cli_name(cptr);
321 if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
322 ++ServerStats->is_ref;
323 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
324 "server %s", cli_name(cptr));
325 return exit_client_msg(cptr, cptr, &me,
326 "Access denied. No conf line for server %s", cli_name(cptr));
328 encr = cli_passwd(cptr);
330 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
331 ++ServerStats->is_ref;
332 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
334 return exit_client_msg(cptr, cptr, &me,
335 "No Access (passwd mismatch) %s", cli_name(cptr));
338 memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
340 if (!feature_bool(FEAT_HUB)) {
341 for (i = 0; i <= HighestFd; i++)
342 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
351 * We want to find IsConnecting() and IsHandshake() too,
353 * The second finds collisions with numeric representation of existing
354 * servers - these shouldn't happen anymore when all upgraded to 2.10.
357 while ((acptr = FindClient(host)) ||
358 (parc > 7 && (acptr = FindNServer(parv[6]))))
361 * This link is trying feed me a server that I already have
362 * access through another path
364 * Do not allow Uworld to do this.
365 * Do not allow servers that are juped.
366 * Do not allow servers that have older link timestamps
368 * Do not allow servers that use the same numeric as an existing
369 * server, but have a different name.
371 * If my ircd.conf sucks, I can try to connect to myself:
374 return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
376 * Detect wrong numeric.
378 if (0 != ircd_strcmp(cli_name(acptr), host)) {
379 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
380 ":SERVER Numeric Collision: %s != %s",
381 cli_name(acptr), host);
382 return exit_client_msg(cptr, cptr, &me,
383 "NUMERIC collision between %s and %s."
384 " Is your server numeric correct ?", host, cli_name(acptr));
387 * Kill our try, if we had one.
389 if (IsConnecting(acptr))
391 if (!active_lh_line && exit_client(cptr, acptr, &me,
392 "Just connected via another link") == CPTR_KILLED)
395 * We can have only ONE 'IsConnecting', 'IsHandshake' or
396 * 'IsServer', because new 'IsConnecting's are refused to
397 * the same server if we already had it.
402 * Avoid other nick collisions...
403 * This is a doubtfull test though, what else would it be
404 * when it has a server.name ?
406 else if (!IsServer(acptr) && !IsHandshake(acptr))
407 return exit_client_msg(cptr, cptr, &me,
408 "Nickname %s already exists!", host);
410 * Our new server might be a juped server,
411 * or someone trying abuse a second Uworld:
413 else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
414 find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
417 return exit_client(cptr, sptr, &me, cli_info(acptr));
418 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
419 ":Received :%s SERVER %s from %s !?!", parv[0],
420 parv[1], cli_name(cptr));
421 return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
424 * Of course we find the handshake this link was before :)
426 else if (IsHandshake(acptr) && acptr == cptr)
429 * Here we have a server nick collision...
430 * We don't want to kill the link that was last /connected,
431 * but we neither want to kill a good (old) link.
432 * Therefor we kill the second youngest link.
436 struct Client* c2ptr = 0;
437 struct Client* c3ptr = acptr;
438 struct Client* ac2ptr;
439 struct Client* ac3ptr;
441 /* Search youngest link: */
442 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
443 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
447 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
448 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
451 if (timestamp > cli_serv(c3ptr)->timestamp)
454 c2ptr = acptr; /* Make sure they differ */
456 /* Search second youngest link: */
457 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
458 if (ac2ptr != c3ptr &&
459 cli_serv(ac2ptr)->timestamp >
460 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
464 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
465 if (ac2ptr != c3ptr &&
466 cli_serv(ac2ptr)->timestamp >
467 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
470 if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
472 /* If timestamps are equal, decide which link to break
475 if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
476 (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
484 n2 = cli_name(c2ptr);
485 n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
490 n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
494 n3 = cli_name(c3ptr);
495 n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
500 n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
502 if (strcmp(n2, n2up) > 0)
504 if (strcmp(n3, n3up) > 0)
506 if (strcmp(n3, n2) > 0)
513 /* Now squit the second youngest link: */
515 return exit_new_server(cptr, sptr, host, timestamp,
516 "server %s already exists and is %ld seconds younger.",
517 host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
518 else if (cli_from(c2ptr) == cptr || IsServer(sptr))
520 struct Client *killedptrfrom = cli_from(c2ptr);
524 * If the L: or H: line also gets rid of this link,
525 * we sent just one squit.
527 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
530 * If breaking the loop here solves the L: or H:
531 * line problem, we don't squit that.
533 if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
538 * If we still have a L: or H: line problem,
539 * we prefer to squit the new server, solving
540 * loop and L:/H: line problem with only one squit.
547 * If the new server was introduced by a server that caused a
548 * Ghost less then 20 seconds ago, this is probably also
549 * a Ghost... (20 seconds is more then enough because all
550 * SERVER messages are at the beginning of a net.burst). --Run
552 if (CurrentTime - cli_serv(cptr)->ghost < 20)
554 killedptrfrom = cli_from(acptr);
555 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
558 else if (exit_client_msg(cptr, c2ptr, &me,
559 "Loop <-- %s (new link is %ld seconds younger)", host,
560 (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
561 (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
564 * Did we kill the incoming server off already ?
566 if (killedptrfrom == cptr)
573 if (LHcptr && a_kills_b_too(LHcptr, acptr))
575 if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
584 * We can't believe it is a lagged server message
585 * when it directly connects to us...
586 * kill the older link at the ghost, rather then
587 * at the second youngest link, assuming it isn't
590 ghost = CurrentTime; /* Mark that it caused a ghost */
591 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
601 return exit_new_server(cptr, sptr, host, timestamp,
602 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
603 "Leaf-only link %s <- %s(%s), check L:",
604 cli_name(cptr), host,
605 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
609 int killed = a_kills_b_too(LHcptr, sptr);
610 if (active_lh_line < 3)
612 if (exit_client_msg(cptr, LHcptr, &me,
613 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
614 "Leaf-only link %s <- %s(%s), check L:",
615 cli_name(cptr), host,
616 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
621 ServerStats->is_ref++;
622 if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
626 * Did we kill the incoming server off already ?
636 * Server is informing about a new server behind
637 * this link. Create REMOTE server structure,
638 * add it to list and propagate word to my other
642 acptr = make_client(cptr, STAT_SERVER);
644 cli_serv(acptr)->prot = prot;
645 cli_serv(acptr)->timestamp = timestamp;
646 cli_hopcount(acptr) = hop;
647 ircd_strncpy(cli_name(acptr), host, HOSTLEN);
648 ircd_strncpy(cli_info(acptr), info, REALLEN);
649 cli_serv(acptr)->up = sptr;
650 cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
651 /* Use cptr, because we do protocol 9 -> 10 translation
652 for numeric nicks ! */
653 SetServerYXX(cptr, acptr, parv[6]);
655 Count_newremoteserver(UserStats);
656 if (Protocol(acptr) < 10)
657 cli_flags(acptr) |= FLAGS_TS8;
658 add_client_to_list(acptr);
663 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
664 cli_name(sptr), cli_name(acptr));
668 * Old sendto_serv_but_one() call removed because we now need to send
669 * different names to different servers (domain name matching).
671 * Personally, I think this is bogus; it's a feature we don't use here.
674 for (i = 0; i <= HighestFd; i++)
676 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
677 bcptr == cptr || IsMe(bcptr))
679 if (0 == match(cli_name(&me), cli_name(acptr)))
681 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
682 cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
688 if (IsUnknown(cptr) || IsHandshake(cptr))
691 cli_serv(cptr)->timestamp = timestamp;
692 cli_serv(cptr)->prot = prot;
693 cli_serv(cptr)->ghost = ghost;
694 SetServerYXX(cptr, cptr, parv[6]);
695 if (start_timestamp > OLDEST_TS)
697 Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
698 cli_serv(&me)->timestamp, start_timestamp));
699 Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
700 "difference %ld", recv_time, timestamp, timestamp - recv_time));
701 if (feature_bool(FEAT_RELIABLE_CLOCK)) {
702 if (start_timestamp < cli_serv(&me)->timestamp)
703 cli_serv(&me)->timestamp = start_timestamp;
705 cli_serv(cptr)->timestamp = TStime();
707 if (start_timestamp < cli_serv(&me)->timestamp) {
708 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
709 "%Tu < %Tu", start_timestamp,
710 cli_serv(&me)->timestamp);
711 cli_serv(&me)->timestamp = start_timestamp;
712 TSoffset += timestamp - recv_time;
713 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
714 (int)(timestamp - recv_time));
715 } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
717 cli_serv(cptr)->timestamp = TStime();
719 else if (timestamp != recv_time) {
721 * Equal start times, we have a collision. Let the connected-to
722 * server decide. This assumes leafs issue more than half of the
723 * connection attempts.
726 cli_serv(cptr)->timestamp = TStime();
727 else if (IsHandshake(cptr)) {
728 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
729 (int)(timestamp - recv_time));
730 TSoffset += timestamp - recv_time;
736 ret = server_estab(cptr, aconf, ajupe);
741 if (feature_bool(FEAT_RELIABLE_CLOCK) &&
742 abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
743 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
744 "timestamp-clock difference of %Td seconds! "
745 "Used SETTIME to correct this.",
746 timestamp - recv_time);
747 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
754 * ms_server - server message handler
756 * parv[0] = sender prefix
757 * parv[1] = servername
759 * parv[3] = start timestamp
760 * parv[4] = link timestamp
761 * parv[5] = major protocol version: P09/P10
762 * parv[parc-1] = serverinfo
764 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
765 * numeric nick mask of this server.
766 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
767 * parv[8] = %<lastmod> - optional parameter only present if there's an
768 * outstanding JUPE; specifies the JUPE's lastmod field
770 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
774 char info[REALLEN + 1];
776 struct Client* acptr;
777 struct Client* bcptr;
778 struct Client* LHcptr = 0;
779 struct ConfItem* aconf = 0;
780 struct ConfItem* lhconf = 0;
781 struct Jupe* ajupe = 0;
784 int active_lh_line = 0;
786 time_t start_timestamp;
787 time_t timestamp = 0;
792 if (IsUserPort(cptr))
793 return exit_client_msg(cptr, cptr, &me,
794 "Cannot connect a server to a user port");
796 recv_time = TStime();
800 return need_more_params(sptr, "SERVER");
801 return exit_client(cptr, cptr, &me, "Need more parameters");
808 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
809 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
811 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
814 prot = atoi(parv[5] + 1);
815 if (prot > atoi(MAJOR_PROTOCOL))
816 prot = atoi(MAJOR_PROTOCOL);
818 * Because the previous test is only in 2.10, the following is needed
819 * till all servers are 2.10:
821 if (IsServer(cptr) && prot > Protocol(cptr))
822 prot = Protocol(cptr);
824 start_timestamp = atoi(parv[3]);
825 timestamp = atoi(parv[4]);
826 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
827 TIME_T_FMT ")", host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
828 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
830 return exit_client_msg(cptr, sptr, &me,
831 "Bogus timestamps (%s %s)", parv[3], parv[4]);
833 ircd_strncpy(info, parv[parc - 1], REALLEN);
834 info[REALLEN] = '\0';
835 if (prot < atoi(MINOR_PROTOCOL)) {
836 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
837 "(%s) from %s", parv[5], cli_name(cptr));
838 return exit_new_server(cptr, sptr, host, timestamp,
839 "Incompatible protocol: %s", parv[5]);
841 if (parc > 9 && *parv[8] == '%')
842 lastmod = atoi(parv[8] + 1);
843 /* If there's a jupe that matches, and it's a global jupe, and the
844 * introducer didn't indicate it knew of the jupe or has an older
845 * version of the jupe, and the connection isn't in a BURST, resynch
848 if ((ajupe = jupe_find(host)) && !JupeIsLocal(ajupe) &&
849 JupeLastMod(ajupe) > lastmod && !IsBurstOrBurstAck(cptr))
850 jupe_resend(cptr, ajupe);
852 * Check for "FRENCH " infection ;-) (actually this should
853 * be replaced with routine to check the hostname syntax in
854 * general). [ This check is still needed, even after the parse
855 * is fixed, because someone can send "SERVER :foo bar " ].
856 * Also, changed to check other "difficult" characters, now
857 * that parse lets all through... --msa
859 if (strlen(host) > HOSTLEN)
860 host[HOSTLEN] = '\0';
861 for (ch = host; *ch; ch++)
862 if (*ch <= ' ' || *ch > '~')
864 if (*ch || !strchr(host, '.')) {
865 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
866 host, cli_name(cptr));
867 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
873 * A local server introduces a new server behind this link.
874 * Check if this is allowed according L:, H: and Q: lines.
877 return exit_client_msg(cptr, cptr, &me,
878 "No server info specified for %s", host);
880 * See if the newly found server is behind a guaranteed
881 * leaf (L-line). If so, close the link.
883 if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
884 (!lhconf->port || (hop > lhconf->port)))
887 * L: lines normally come in pairs, here we try to
888 * make sure that the oldest link is squitted, not
892 if (timestamp <= cli_serv(cptr)->timestamp)
893 LHcptr = 0; /* Kill incoming server */
895 LHcptr = cptr; /* Squit ourselfs */
897 else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
898 (lhconf->port && (hop > lhconf->port)))
900 struct Client *ac3ptr;
902 /* Look for net junction causing this: */
903 LHcptr = 0; /* incoming server */
904 if (*parv[5] != 'J') {
905 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
906 if (IsJunction(ac3ptr)) {
915 if (IsUnknown(cptr) || IsHandshake(cptr))
920 * A local link that is still in undefined state wants
921 * to be a SERVER. Check if this is allowed and change
922 * status accordingly...
925 * If there is more then one server on the same machine
926 * that we try to connect to, it could be that the /CONNECT
927 * <mask> caused this connect to be put at the wrong place
928 * in the hashtable. --Run
929 * Same thing for Unknown connections that first send NICK.
931 * Better check if the two strings are (caseless) identical
932 * and not mess with hash internals.
935 if ((!(EmptyString(cli_name(cptr))))
936 && (IsUnknown(cptr) || IsHandshake(cptr))
937 && 0 != ircd_strcmp(cli_name(cptr), host))
938 hChangeClient(cptr, host);
939 ircd_strncpy(cli_name(cptr), host, HOSTLEN);
940 ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
941 cli_hopcount(cptr) = hop;
943 /* check connection rules */
944 if (0 != conf_eval_crule(host, CRULE_ALL)) {
945 ServerStats->is_ref++;
946 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
947 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
949 if (conf_check_server(cptr)) {
950 ++ServerStats->is_ref;
951 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
952 "from %s.", cli_name(cptr));
953 return exit_client(cptr, cptr, &me, "No C conf lines");
956 host = cli_name(cptr);
960 if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
961 ++ServerStats->is_ref;
962 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
963 "server %s", cli_name(cptr));
964 return exit_client_msg(cptr, cptr, &me,
965 "Access denied. No conf line for server %s", cli_name(cptr));
967 encr = cli_passwd(cptr);
969 if (*(aconf->passwd) && !!strcmp(aconf->passwd, encr)) {
970 ++ServerStats->is_ref;
971 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
973 return exit_client_msg(cptr, cptr, &me,
974 "No Access (passwd mismatch) %s", cli_name(cptr));
976 memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
978 if (!feature_bool(FEAT_HUB)) {
979 for (i = 0; i <= HighestFd; i++)
980 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
989 * We want to find IsConnecting() and IsHandshake() too,
991 * The second finds collisions with numeric representation of existing
992 * servers - these shouldn't happen anymore when all upgraded to 2.10.
995 while ((acptr = FindClient(host)) ||
996 (parc > 7 && (acptr = FindNServer(parv[6]))))
999 * This link is trying feed me a server that I already have
1000 * access through another path
1002 * Do not allow Uworld to do this.
1003 * Do not allow servers that are juped.
1004 * Do not allow servers that have older link timestamps
1006 * Do not allow servers that use the same numeric as an existing
1007 * server, but have a different name.
1009 * If my ircd.conf sucks, I can try to connect to myself:
1012 return exit_client_msg(cptr, cptr, &me,
1013 "nick collision with me, check server number in M:? (%s)", host);
1015 * Detect wrong numeric.
1017 if (0 != ircd_strcmp(cli_name(acptr), host))
1019 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1020 ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
1022 return exit_client_msg(cptr, cptr, &me,
1023 "NUMERIC collision between %s and %s."
1024 " Is your server numeric correct ?", host, cli_name(acptr));
1027 * Kill our try, if we had one.
1029 if (IsConnecting(acptr))
1031 if (!active_lh_line && exit_client(cptr, acptr, &me,
1032 "Just connected via another link") == CPTR_KILLED)
1035 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1036 * 'IsServer', because new 'IsConnecting's are refused to
1037 * the same server if we already had it.
1042 * Avoid other nick collisions...
1043 * This is a doubtfull test though, what else would it be
1044 * when it has a server.name ?
1046 else if (!IsServer(acptr) && !IsHandshake(acptr))
1047 return exit_client_msg(cptr, cptr, &me,
1048 "Nickname %s already exists!", host);
1050 * Our new server might be a juped server,
1051 * or someone trying abuse a second Uworld:
1053 else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
1054 find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
1056 if (!IsServer(sptr))
1057 return exit_client(cptr, sptr, &me, cli_info(acptr));
1058 sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1059 "from %s !?!", parv[0], parv[1], cli_name(cptr));
1060 return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
1063 * Of course we find the handshake this link was before :)
1065 else if (IsHandshake(acptr) && acptr == cptr)
1068 * Here we have a server nick collision...
1069 * We don't want to kill the link that was last /connected,
1070 * but we neither want to kill a good (old) link.
1071 * Therefor we kill the second youngest link.
1075 struct Client* c2ptr = 0;
1076 struct Client* c3ptr = acptr;
1077 struct Client* ac2ptr;
1078 struct Client* ac3ptr;
1080 /* Search youngest link: */
1081 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1082 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1086 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1087 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1090 if (timestamp > cli_serv(c3ptr)->timestamp)
1093 c2ptr = acptr; /* Make sure they differ */
1095 /* Search second youngest link: */
1096 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1097 if (ac2ptr != c3ptr &&
1098 cli_serv(ac2ptr)->timestamp >
1099 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1103 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1104 if (ac2ptr != c3ptr &&
1105 cli_serv(ac2ptr)->timestamp >
1106 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1109 if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1111 /* If timestamps are equal, decide which link to break
1114 if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
1115 (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
1123 n2 = cli_name(c2ptr);
1124 n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
1129 n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1133 n3 = cli_name(c3ptr);
1134 n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
1139 n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1141 if (strcmp(n2, n2up) > 0)
1143 if (strcmp(n3, n3up) > 0)
1145 if (strcmp(n3, n2) > 0)
1152 /* Now squit the second youngest link: */
1154 return exit_new_server(cptr, sptr, host, timestamp,
1155 "server %s already exists and is %ld seconds younger.",
1156 host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
1157 else if (cli_from(c2ptr) == cptr || IsServer(sptr))
1159 struct Client *killedptrfrom = cli_from(c2ptr);
1163 * If the L: or H: line also gets rid of this link,
1164 * we sent just one squit.
1166 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1169 * If breaking the loop here solves the L: or H:
1170 * line problem, we don't squit that.
1172 if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1177 * If we still have a L: or H: line problem,
1178 * we prefer to squit the new server, solving
1179 * loop and L:/H: line problem with only one squit.
1186 * If the new server was introduced by a server that caused a
1187 * Ghost less then 20 seconds ago, this is probably also
1188 * a Ghost... (20 seconds is more then enough because all
1189 * SERVER messages are at the beginning of a net.burst). --Run
1191 if (CurrentTime - cli_serv(cptr)->ghost < 20)
1193 killedptrfrom = cli_from(acptr);
1194 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1197 else if (exit_client_msg(cptr, c2ptr, &me,
1198 "Loop <-- %s (new link is %ld seconds younger)", host,
1199 (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
1200 (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
1203 * Did we kill the incoming server off already ?
1205 if (killedptrfrom == cptr)
1212 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1214 if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1223 * We can't believe it is a lagged server message
1224 * when it directly connects to us...
1225 * kill the older link at the ghost, rather then
1226 * at the second youngest link, assuming it isn't
1229 ghost = CurrentTime; /* Mark that it caused a ghost */
1230 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1240 return exit_new_server(cptr, sptr, host, timestamp,
1241 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1242 cli_name(cptr), host,
1243 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1247 int killed = a_kills_b_too(LHcptr, sptr);
1248 if (active_lh_line < 3)
1250 if (exit_client_msg(cptr, LHcptr, &me,
1251 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1252 cli_name(cptr), host,
1253 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1258 ServerStats->is_ref++;
1259 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1263 * Did we kill the incoming server off already ?
1273 * Server is informing about a new server behind
1274 * this link. Create REMOTE server structure,
1275 * add it to list and propagate word to my other
1279 acptr = make_client(cptr, STAT_SERVER);
1281 cli_serv(acptr)->prot = prot;
1282 cli_serv(acptr)->timestamp = timestamp;
1283 cli_hopcount(acptr) = hop;
1284 ircd_strncpy(cli_name(acptr), host, HOSTLEN);
1285 ircd_strncpy(cli_info(acptr), info, REALLEN);
1286 cli_serv(acptr)->up = sptr;
1287 cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
1288 /* Use cptr, because we do protocol 9 -> 10 translation
1289 for numeric nicks ! */
1290 SetServerYXX(cptr, acptr, parv[6]);
1292 Count_newremoteserver(UserStats);
1293 if (Protocol(acptr) < 10)
1294 cli_flags(acptr) |= FLAGS_TS8;
1295 add_client_to_list(acptr);
1297 if (*parv[5] == 'J')
1300 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1301 cli_name(sptr), cli_name(acptr));
1305 * Old sendto_serv_but_one() call removed because we now need to send
1306 * different names to different servers (domain name matching).
1308 for (i = 0; i <= HighestFd; i++)
1310 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1311 bcptr == cptr || IsMe(bcptr))
1313 if (0 == match(cli_name(&me), cli_name(acptr)))
1315 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1316 cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
1322 if (IsUnknown(cptr) || IsHandshake(cptr))
1325 cli_serv(cptr)->timestamp = timestamp;
1326 cli_serv(cptr)->prot = prot;
1327 cli_serv(cptr)->ghost = ghost;
1328 SetServerYXX(cptr, cptr, parv[6]);
1329 if (start_timestamp > OLDEST_TS)
1331 Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
1332 cli_serv(&me)->timestamp, start_timestamp));
1333 Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
1334 "difference %ld", recv_time, timestamp, timestamp - recv_time));
1335 if (feature_bool(FEAT_RELIABLE_CLOCK)) {
1336 if (start_timestamp < cli_serv(&me)->timestamp)
1337 cli_serv(&me)->timestamp = start_timestamp;
1338 if (IsUnknown(cptr))
1339 cli_serv(cptr)->timestamp = TStime();
1341 if (start_timestamp < cli_serv(&me)->timestamp) {
1342 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1343 "%Tu < %Tu", start_timestamp,
1344 cli_serv(&me)->timestamp);
1345 cli_serv(&me)->timestamp = start_timestamp;
1346 TSoffset += timestamp - recv_time;
1347 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1348 (int)(timestamp - recv_time));
1349 } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
1351 cli_serv(cptr)->timestamp = TStime();
1353 else if (timestamp != recv_time) {
1355 * Equal start times, we have a collision. Let the connected-to
1356 * server decide. This assumes leafs issue more than half of the
1357 * connection attempts.
1359 if (IsUnknown(cptr))
1360 cli_serv(cptr)->timestamp = TStime();
1361 else if (IsHandshake(cptr)) {
1362 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1363 (int)(timestamp - recv_time));
1364 TSoffset += timestamp - recv_time;
1370 ret = server_estab(cptr, aconf, ajupe);
1375 if (feature_bool(FEAT_RELIABLE_CLOCK) &&
1376 abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
1377 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1378 "timestamp-clock difference of %Td seconds! Used "
1379 "SETTIME to correct this.", timestamp - recv_time);
1380 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
1391 * parv[0] = sender prefix
1392 * parv[1] = servername
1393 * parv[2] = hopcount
1394 * parv[3] = start timestamp
1395 * parv[4] = link timestamp
1396 * parv[5] = major protocol version: P09/P10
1397 * parv[parc-1] = serverinfo
1399 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1400 * numeric nick mask of this server.
1401 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1403 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1407 char info[REALLEN + 1];
1409 struct Client* acptr;
1410 struct Client* bcptr;
1411 struct Client* LHcptr = 0;
1412 struct ConfItem* aconf = 0;
1413 struct ConfItem* lhconf = 0;
1414 struct Jupe* ajupe = 0;
1417 int active_lh_line = 0;
1418 unsigned short prot;
1419 time_t start_timestamp;
1420 time_t timestamp = 0;
1426 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1430 if (IsUserPort(cptr))
1431 return exit_client_msg(cptr, cptr, &me,
1432 "You cannot connect a server to a user port; connect to %s port %u",
1433 me.name, server_port);
1435 recv_time = TStime();
1439 return need_more_params(sptr, "SERVER");
1440 return exit_client(cptr, cptr, &me, "Need more parameters");
1446 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1447 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1449 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1452 prot = atoi(parv[5] + 1);
1453 if (prot > atoi(MAJOR_PROTOCOL))
1454 prot = atoi(MAJOR_PROTOCOL);
1456 * Because the previous test is only in 2.10, the following is needed
1457 * till all servers are 2.10:
1459 if (IsServer(cptr) && prot > Protocol(cptr))
1460 prot = Protocol(cptr);
1461 hop = atoi(parv[2]);
1462 start_timestamp = atoi(parv[3]);
1463 timestamp = atoi(parv[4]);
1464 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1465 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1466 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1468 return exit_client_msg(cptr, sptr, &me,
1469 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1471 ircd_strncpy(info, parv[parc - 1], REALLEN);
1472 info[REALLEN] = '\0';
1473 if (prot < atoi(MINOR_PROTOCOL)) {
1474 sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1475 parv[5], cptr->name);
1476 return exit_new_server(cptr, sptr, host, timestamp,
1477 "Incompatible protocol: %s", parv[5]);
1480 * Check for "FRENCH " infection ;-) (actually this should
1481 * be replaced with routine to check the hostname syntax in
1482 * general). [ This check is still needed, even after the parse
1483 * is fixed, because someone can send "SERVER :foo bar " ].
1484 * Also, changed to check other "difficult" characters, now
1485 * that parse lets all through... --msa
1487 if (strlen(host) > HOSTLEN)
1488 host[HOSTLEN] = '\0';
1489 for (ch = host; *ch; ch++)
1490 if (*ch <= ' ' || *ch > '~')
1492 if (*ch || !strchr(host, '.'))
1494 sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1495 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1501 * A local server introduces a new server behind this link.
1502 * Check if this is allowed according L:, H: and Q: lines.
1504 if (info[0] == '\0')
1505 return exit_client_msg(cptr, cptr, &me,
1506 "No server info specified for %s", host);
1508 * See if the newly found server is behind a guaranteed
1509 * leaf (L-line). If so, close the link.
1511 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1512 (!lhconf->port || (hop > lhconf->port)))
1515 * L: lines normally come in pairs, here we try to
1516 * make sure that the oldest link is squitted, not
1520 if (timestamp <= cptr->serv->timestamp)
1521 LHcptr = 0; /* Kill incoming server */
1523 LHcptr = cptr; /* Squit ourselfs */
1525 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1526 (lhconf->port && (hop > lhconf->port)))
1528 struct Client *ac3ptr;
1530 /* Look for net junction causing this: */
1531 LHcptr = 0; /* incoming server */
1532 if (*parv[5] != 'J') {
1533 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1534 if (IsJunction(ac3ptr)) {
1543 if (IsUnknown(cptr) || IsHandshake(cptr))
1548 * A local link that is still in undefined state wants
1549 * to be a SERVER. Check if this is allowed and change
1550 * status accordingly...
1553 * If there is more then one server on the same machine
1554 * that we try to connect to, it could be that the /CONNECT
1555 * <mask> caused this connect to be put at the wrong place
1556 * in the hashtable. --Run
1557 * Same thing for Unknown connections that first send NICK.
1559 * Better check if the two strings are (caseless) identical
1560 * and not mess with hash internals.
1563 if ((!(EmptyString(cptr->name)))
1564 && (IsUnknown(cptr) || IsHandshake(cptr))
1565 && 0 != ircd_strcmp(cptr->name, host))
1566 hChangeClient(cptr, host);
1567 ircd_strncpy(cptr->name, host, HOSTLEN);
1568 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1569 cptr->hopcount = hop;
1571 /* check connection rules */
1572 if (0 != conf_eval_crule(host, CRULE_ALL)) {
1573 ServerStats->is_ref++;
1574 sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1575 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1577 if (conf_check_server(cptr)) {
1578 ++ServerStats->is_ref;
1579 sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1580 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1587 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1588 ++ServerStats->is_ref;
1590 sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1591 return exit_client_msg(cptr, cptr, &me,
1592 "Access denied. No conf line for server %s", cptr->name);
1594 sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1596 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1598 sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1599 "\"general.undernet.org\"", cptr->name);
1600 return exit_client_msg(cptr, cptr, &me,
1601 "No C/N lines for server %s", cptr->name);
1603 #endif /* GODMODE */
1605 #ifdef CRYPT_LINK_PASSWORD
1606 /* passwd may be NULL. Head it off at the pass... */
1609 encr = ircd_crypt(cptr->passwd, aconf->passwd);
1614 encr = cptr->passwd;
1615 #endif /* CRYPT_LINK_PASSWORD */
1617 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1618 ++ServerStats->is_ref;
1619 sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1620 return exit_client_msg(cptr, cptr, &me,
1621 "No Access (passwd mismatch) %s", cptr->name);
1623 #endif /* not GODMODE */
1624 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1627 for (i = 0; i <= HighestFd; i++)
1628 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1637 * We want to find IsConnecting() and IsHandshake() too,
1639 * The second finds collisions with numeric representation of existing
1640 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1643 while ((acptr = FindClient(host)) ||
1644 (parc > 7 && (acptr = FindNServer(parv[6]))))
1647 * This link is trying feed me a server that I already have
1648 * access through another path
1650 * Do not allow Uworld to do this.
1651 * Do not allow servers that are juped.
1652 * Do not allow servers that have older link timestamps
1654 * Do not allow servers that use the same numeric as an existing
1655 * server, but have a different name.
1657 * If my ircd.conf sucks, I can try to connect to myself:
1660 return exit_client_msg(cptr, cptr, &me,
1661 "nick collision with me, check server number in M:? (%s)", host);
1663 * Detect wrong numeric.
1665 if (0 != ircd_strcmp(acptr->name, host))
1667 sendto_serv_butone(cptr, /* XXX DEAD */
1668 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1669 me.name, acptr->name, host);
1670 return exit_client_msg(cptr, cptr, &me,
1671 "NUMERIC collision between %s and %s."
1672 " Is your server numeric correct ?", host, acptr->name);
1675 * Kill our try, if we had one.
1677 if (IsConnecting(acptr))
1679 if (!active_lh_line && exit_client(cptr, acptr, &me,
1680 "Just connected via another link") == CPTR_KILLED)
1683 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1684 * 'IsServer', because new 'IsConnecting's are refused to
1685 * the same server if we already had it.
1690 * Avoid other nick collisions...
1691 * This is a doubtfull test though, what else would it be
1692 * when it has a server.name ?
1694 else if (!IsServer(acptr) && !IsHandshake(acptr))
1695 return exit_client_msg(cptr, cptr, &me,
1696 "Nickname %s already exists!", host);
1698 * Our new server might be a juped server,
1699 * or someone trying abuse a second Uworld:
1701 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1702 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1704 if (!IsServer(sptr))
1705 return exit_client(cptr, sptr, &me, acptr->info);
1706 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1707 me.name, parv[0], parv[1], cptr->name);
1708 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1711 * Of course we find the handshake this link was before :)
1713 else if (IsHandshake(acptr) && acptr == cptr)
1716 * Here we have a server nick collision...
1717 * We don't want to kill the link that was last /connected,
1718 * but we neither want to kill a good (old) link.
1719 * Therefor we kill the second youngest link.
1723 struct Client* c2ptr = 0;
1724 struct Client* c3ptr = acptr;
1725 struct Client* ac2ptr;
1726 struct Client* ac3ptr;
1728 /* Search youngest link: */
1729 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1730 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1734 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1735 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1738 if (timestamp > c3ptr->serv->timestamp)
1741 c2ptr = acptr; /* Make sure they differ */
1743 /* Search second youngest link: */
1744 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1745 if (ac2ptr != c3ptr &&
1746 ac2ptr->serv->timestamp >
1747 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1751 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1752 if (ac2ptr != c3ptr &&
1753 ac2ptr->serv->timestamp >
1754 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1757 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1759 /* If timestamps are equal, decide which link to break
1762 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1763 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1772 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1777 n2up = IsServer(sptr) ? sptr->name : me.name;
1782 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1787 n3up = IsServer(sptr) ? sptr->name : me.name;
1789 if (strcmp(n2, n2up) > 0)
1791 if (strcmp(n3, n3up) > 0)
1793 if (strcmp(n3, n2) > 0)
1800 /* Now squit the second youngest link: */
1802 return exit_new_server(cptr, sptr, host, timestamp,
1803 "server %s already exists and is %ld seconds younger.",
1804 host, (long)acptr->serv->timestamp - (long)timestamp);
1805 else if (c2ptr->from == cptr || IsServer(sptr))
1807 struct Client *killedptrfrom = c2ptr->from;
1811 * If the L: or H: line also gets rid of this link,
1812 * we sent just one squit.
1814 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1817 * If breaking the loop here solves the L: or H:
1818 * line problem, we don't squit that.
1820 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1825 * If we still have a L: or H: line problem,
1826 * we prefer to squit the new server, solving
1827 * loop and L:/H: line problem with only one squit.
1834 * If the new server was introduced by a server that caused a
1835 * Ghost less then 20 seconds ago, this is probably also
1836 * a Ghost... (20 seconds is more then enough because all
1837 * SERVER messages are at the beginning of a net.burst). --Run
1839 if (CurrentTime - cptr->serv->ghost < 20)
1841 killedptrfrom = acptr->from;
1842 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1845 else if (exit_client_msg(cptr, c2ptr, &me,
1846 "Loop <-- %s (new link is %ld seconds younger)", host,
1847 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1848 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1851 * Did we kill the incoming server off already ?
1853 if (killedptrfrom == cptr)
1860 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1862 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1871 * We can't believe it is a lagged server message
1872 * when it directly connects to us...
1873 * kill the older link at the ghost, rather then
1874 * at the second youngest link, assuming it isn't
1877 ghost = CurrentTime; /* Mark that it caused a ghost */
1878 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1888 return exit_new_server(cptr, sptr, host, timestamp,
1889 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1891 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1895 int killed = a_kills_b_too(LHcptr, sptr);
1896 if (active_lh_line < 3)
1898 if (exit_client_msg(cptr, LHcptr, &me,
1899 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1901 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1906 ServerStats->is_ref++;
1907 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1911 * Did we kill the incoming server off already ?
1921 * Server is informing about a new server behind
1922 * this link. Create REMOTE server structure,
1923 * add it to list and propagate word to my other
1927 acptr = make_client(cptr, STAT_SERVER);
1929 acptr->serv->prot = prot;
1930 acptr->serv->timestamp = timestamp;
1931 acptr->hopcount = hop;
1932 ircd_strncpy(acptr->name, host, HOSTLEN);
1933 ircd_strncpy(acptr->info, info, REALLEN);
1934 acptr->serv->up = sptr;
1935 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1936 /* Use cptr, because we do protocol 9 -> 10 translation
1937 for numeric nicks ! */
1938 SetServerYXX(cptr, acptr, parv[6]);
1940 Count_newremoteserver(UserStats);
1941 if (Protocol(acptr) < 10)
1942 acptr->flags |= FLAGS_TS8;
1943 add_client_to_list(acptr);
1945 if (*parv[5] == 'J')
1948 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
1949 sptr->name, acptr->name);
1953 * Old sendto_serv_but_one() call removed because we now need to send
1954 * different names to different servers (domain name matching).
1956 for (i = 0; i <= HighestFd; i++)
1958 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1959 bcptr == cptr || IsMe(bcptr))
1961 if (0 == match(me.name, acptr->name))
1963 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
1964 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1965 NumServCap(acptr), acptr->info);
1970 if (IsUnknown(cptr) || IsHandshake(cptr))
1973 cptr->serv->timestamp = timestamp;
1974 cptr->serv->prot = prot;
1975 cptr->serv->ghost = ghost;
1976 SetServerYXX(cptr, cptr, parv[6]);
1977 if (start_timestamp > OLDEST_TS)
1979 #ifndef RELIABLE_CLOCK
1981 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
1982 TIME_T_FMT, me.serv->timestamp, start_timestamp);
1983 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
1984 TIME_T_FMT " ; difference %ld",
1985 recv_time, timestamp, timestamp - recv_time);
1987 if (start_timestamp < me.serv->timestamp)
1989 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
1990 start_timestamp, me.serv->timestamp);
1991 me.serv->timestamp = start_timestamp;
1992 TSoffset += timestamp - recv_time;
1993 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
1995 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1996 cptr->serv->timestamp = TStime();
1998 else if (timestamp != recv_time)
2001 * Equal start times, we have a collision. Let the connected-to server
2002 * decide. This assumes leafs issue more than half of the connection
2005 if (IsUnknown(cptr))
2006 cptr->serv->timestamp = TStime();
2007 else if (IsHandshake(cptr))
2009 sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
2010 (int)(timestamp - recv_time));
2011 TSoffset += timestamp - recv_time;
2014 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2015 if (start_timestamp < me.serv->timestamp)
2016 me.serv->timestamp = start_timestamp;
2017 if (IsUnknown(cptr))
2018 cptr->serv->timestamp = TStime();
2022 ret = server_estab(cptr, aconf); /* XXX DEAD */
2026 #ifdef RELIABLE_CLOCK
2027 if (abs(cptr->serv->timestamp - recv_time) > 30)
2029 sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2030 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2031 " this.", timestamp - recv_time);
2032 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2033 me.name, TStime(), me.name);