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);
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)
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;
783 int active_lh_line = 0;
785 time_t start_timestamp;
786 time_t timestamp = 0;
790 if (IsUserPort(cptr))
791 return exit_client_msg(cptr, cptr, &me,
792 "Cannot connect a server to a user port");
794 recv_time = TStime();
798 return need_more_params(sptr, "SERVER");
799 return exit_client(cptr, cptr, &me, "Need more parameters");
806 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
807 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
809 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
812 prot = atoi(parv[5] + 1);
813 if (prot > atoi(MAJOR_PROTOCOL))
814 prot = atoi(MAJOR_PROTOCOL);
816 * Because the previous test is only in 2.10, the following is needed
817 * till all servers are 2.10:
819 if (IsServer(cptr) && prot > Protocol(cptr))
820 prot = Protocol(cptr);
822 start_timestamp = atoi(parv[3]);
823 timestamp = atoi(parv[4]);
824 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
825 host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
826 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
828 return exit_client_msg(cptr, sptr, &me,
829 "Bogus timestamps (%s %s)", parv[3], parv[4]);
831 ircd_strncpy(info, parv[parc - 1], REALLEN);
832 info[REALLEN] = '\0';
833 if (prot < atoi(MINOR_PROTOCOL)) {
834 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
835 "(%s) from %s", parv[5], cli_name(cptr));
836 return exit_new_server(cptr, sptr, host, timestamp,
837 "Incompatible protocol: %s", parv[5]);
840 * Check for "FRENCH " infection ;-) (actually this should
841 * be replaced with routine to check the hostname syntax in
842 * general). [ This check is still needed, even after the parse
843 * is fixed, because someone can send "SERVER :foo bar " ].
844 * Also, changed to check other "difficult" characters, now
845 * that parse lets all through... --msa
847 if (strlen(host) > HOSTLEN)
848 host[HOSTLEN] = '\0';
849 for (ch = host; *ch; ch++)
850 if (*ch <= ' ' || *ch > '~')
852 if (*ch || !strchr(host, '.')) {
853 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
854 host, cli_name(cptr));
855 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
861 * A local server introduces a new server behind this link.
862 * Check if this is allowed according L:, H: and Q: lines.
865 return exit_client_msg(cptr, cptr, &me,
866 "No server info specified for %s", host);
868 * See if the newly found server is behind a guaranteed
869 * leaf (L-line). If so, close the link.
871 if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
872 (!lhconf->port || (hop > lhconf->port)))
875 * L: lines normally come in pairs, here we try to
876 * make sure that the oldest link is squitted, not
880 if (timestamp <= cli_serv(cptr)->timestamp)
881 LHcptr = 0; /* Kill incoming server */
883 LHcptr = cptr; /* Squit ourselfs */
885 else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
886 (lhconf->port && (hop > lhconf->port)))
888 struct Client *ac3ptr;
890 /* Look for net junction causing this: */
891 LHcptr = 0; /* incoming server */
892 if (*parv[5] != 'J') {
893 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
894 if (IsJunction(ac3ptr)) {
903 if (IsUnknown(cptr) || IsHandshake(cptr))
908 * A local link that is still in undefined state wants
909 * to be a SERVER. Check if this is allowed and change
910 * status accordingly...
913 * If there is more then one server on the same machine
914 * that we try to connect to, it could be that the /CONNECT
915 * <mask> caused this connect to be put at the wrong place
916 * in the hashtable. --Run
917 * Same thing for Unknown connections that first send NICK.
919 * Better check if the two strings are (caseless) identical
920 * and not mess with hash internals.
923 if ((!(EmptyString(cli_name(cptr))))
924 && (IsUnknown(cptr) || IsHandshake(cptr))
925 && 0 != ircd_strcmp(cli_name(cptr), host))
926 hChangeClient(cptr, host);
927 ircd_strncpy(cli_name(cptr), host, HOSTLEN);
928 ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
929 cli_hopcount(cptr) = hop;
931 /* check connection rules */
932 if (0 != conf_eval_crule(host, CRULE_ALL)) {
933 ServerStats->is_ref++;
934 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
935 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
937 if (conf_check_server(cptr)) {
938 ++ServerStats->is_ref;
939 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
940 "from %s.", cli_name(cptr));
941 return exit_client(cptr, cptr, &me, "No C conf lines");
944 host = cli_name(cptr);
948 if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
949 ++ServerStats->is_ref;
950 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
951 "server %s", cli_name(cptr));
952 return exit_client_msg(cptr, cptr, &me,
953 "Access denied. No conf line for server %s", cli_name(cptr));
955 encr = cli_passwd(cptr);
957 if (*(aconf->passwd) && !!strcmp(aconf->passwd, encr)) {
958 ++ServerStats->is_ref;
959 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
961 return exit_client_msg(cptr, cptr, &me,
962 "No Access (passwd mismatch) %s", cli_name(cptr));
964 memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
966 if (!feature_bool(FEAT_HUB)) {
967 for (i = 0; i <= HighestFd; i++)
968 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
977 * We want to find IsConnecting() and IsHandshake() too,
979 * The second finds collisions with numeric representation of existing
980 * servers - these shouldn't happen anymore when all upgraded to 2.10.
983 while ((acptr = FindClient(host)) ||
984 (parc > 7 && (acptr = FindNServer(parv[6]))))
987 * This link is trying feed me a server that I already have
988 * access through another path
990 * Do not allow Uworld to do this.
991 * Do not allow servers that are juped.
992 * Do not allow servers that have older link timestamps
994 * Do not allow servers that use the same numeric as an existing
995 * server, but have a different name.
997 * If my ircd.conf sucks, I can try to connect to myself:
1000 return exit_client_msg(cptr, cptr, &me,
1001 "nick collision with me, check server number in M:? (%s)", host);
1003 * Detect wrong numeric.
1005 if (0 != ircd_strcmp(cli_name(acptr), host))
1007 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1008 ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
1010 return exit_client_msg(cptr, cptr, &me,
1011 "NUMERIC collision between %s and %s."
1012 " Is your server numeric correct ?", host, cli_name(acptr));
1015 * Kill our try, if we had one.
1017 if (IsConnecting(acptr))
1019 if (!active_lh_line && exit_client(cptr, acptr, &me,
1020 "Just connected via another link") == CPTR_KILLED)
1023 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1024 * 'IsServer', because new 'IsConnecting's are refused to
1025 * the same server if we already had it.
1030 * Avoid other nick collisions...
1031 * This is a doubtfull test though, what else would it be
1032 * when it has a server.name ?
1034 else if (!IsServer(acptr) && !IsHandshake(acptr))
1035 return exit_client_msg(cptr, cptr, &me,
1036 "Nickname %s already exists!", host);
1038 * Our new server might be a juped server,
1039 * or someone trying abuse a second Uworld:
1041 else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
1042 find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
1044 if (!IsServer(sptr))
1045 return exit_client(cptr, sptr, &me, cli_info(acptr));
1046 sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1047 "from %s !?!", parv[0], parv[1], cli_name(cptr));
1048 return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
1051 * Of course we find the handshake this link was before :)
1053 else if (IsHandshake(acptr) && acptr == cptr)
1056 * Here we have a server nick collision...
1057 * We don't want to kill the link that was last /connected,
1058 * but we neither want to kill a good (old) link.
1059 * Therefor we kill the second youngest link.
1063 struct Client* c2ptr = 0;
1064 struct Client* c3ptr = acptr;
1065 struct Client* ac2ptr;
1066 struct Client* ac3ptr;
1068 /* Search youngest link: */
1069 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1070 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1074 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1075 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1078 if (timestamp > cli_serv(c3ptr)->timestamp)
1081 c2ptr = acptr; /* Make sure they differ */
1083 /* Search second youngest link: */
1084 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1085 if (ac2ptr != c3ptr &&
1086 cli_serv(ac2ptr)->timestamp >
1087 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1091 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1092 if (ac2ptr != c3ptr &&
1093 cli_serv(ac2ptr)->timestamp >
1094 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1097 if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1099 /* If timestamps are equal, decide which link to break
1102 if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
1103 (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
1111 n2 = cli_name(c2ptr);
1112 n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
1117 n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1121 n3 = cli_name(c3ptr);
1122 n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
1127 n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1129 if (strcmp(n2, n2up) > 0)
1131 if (strcmp(n3, n3up) > 0)
1133 if (strcmp(n3, n2) > 0)
1140 /* Now squit the second youngest link: */
1142 return exit_new_server(cptr, sptr, host, timestamp,
1143 "server %s already exists and is %ld seconds younger.",
1144 host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
1145 else if (cli_from(c2ptr) == cptr || IsServer(sptr))
1147 struct Client *killedptrfrom = cli_from(c2ptr);
1151 * If the L: or H: line also gets rid of this link,
1152 * we sent just one squit.
1154 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1157 * If breaking the loop here solves the L: or H:
1158 * line problem, we don't squit that.
1160 if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1165 * If we still have a L: or H: line problem,
1166 * we prefer to squit the new server, solving
1167 * loop and L:/H: line problem with only one squit.
1174 * If the new server was introduced by a server that caused a
1175 * Ghost less then 20 seconds ago, this is probably also
1176 * a Ghost... (20 seconds is more then enough because all
1177 * SERVER messages are at the beginning of a net.burst). --Run
1179 if (CurrentTime - cli_serv(cptr)->ghost < 20)
1181 killedptrfrom = cli_from(acptr);
1182 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1185 else if (exit_client_msg(cptr, c2ptr, &me,
1186 "Loop <-- %s (new link is %ld seconds younger)", host,
1187 (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
1188 (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
1191 * Did we kill the incoming server off already ?
1193 if (killedptrfrom == cptr)
1200 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1202 if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1211 * We can't believe it is a lagged server message
1212 * when it directly connects to us...
1213 * kill the older link at the ghost, rather then
1214 * at the second youngest link, assuming it isn't
1217 ghost = CurrentTime; /* Mark that it caused a ghost */
1218 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1228 return exit_new_server(cptr, sptr, host, timestamp,
1229 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1230 cli_name(cptr), host,
1231 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1235 int killed = a_kills_b_too(LHcptr, sptr);
1236 if (active_lh_line < 3)
1238 if (exit_client_msg(cptr, LHcptr, &me,
1239 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1240 cli_name(cptr), host,
1241 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1246 ServerStats->is_ref++;
1247 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1251 * Did we kill the incoming server off already ?
1261 * Server is informing about a new server behind
1262 * this link. Create REMOTE server structure,
1263 * add it to list and propagate word to my other
1267 acptr = make_client(cptr, STAT_SERVER);
1269 cli_serv(acptr)->prot = prot;
1270 cli_serv(acptr)->timestamp = timestamp;
1271 cli_hopcount(acptr) = hop;
1272 ircd_strncpy(cli_name(acptr), host, HOSTLEN);
1273 ircd_strncpy(cli_info(acptr), info, REALLEN);
1274 cli_serv(acptr)->up = sptr;
1275 cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
1276 /* Use cptr, because we do protocol 9 -> 10 translation
1277 for numeric nicks ! */
1278 SetServerYXX(cptr, acptr, parv[6]);
1280 Count_newremoteserver(UserStats);
1281 if (Protocol(acptr) < 10)
1282 cli_flags(acptr) |= FLAGS_TS8;
1283 add_client_to_list(acptr);
1285 if (*parv[5] == 'J')
1288 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1289 cli_name(sptr), cli_name(acptr));
1293 * Old sendto_serv_but_one() call removed because we now need to send
1294 * different names to different servers (domain name matching).
1296 for (i = 0; i <= HighestFd; i++)
1298 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1299 bcptr == cptr || IsMe(bcptr))
1301 if (0 == match(cli_name(&me), cli_name(acptr)))
1303 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1304 cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
1310 if (IsUnknown(cptr) || IsHandshake(cptr))
1313 cli_serv(cptr)->timestamp = timestamp;
1314 cli_serv(cptr)->prot = prot;
1315 cli_serv(cptr)->ghost = ghost;
1316 SetServerYXX(cptr, cptr, parv[6]);
1317 if (start_timestamp > OLDEST_TS)
1319 Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
1320 cli_serv(&me)->timestamp, start_timestamp));
1321 Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
1322 "difference %ld", recv_time, timestamp, timestamp - recv_time));
1323 if (feature_bool(FEAT_RELIABLE_CLOCK)) {
1324 if (start_timestamp < cli_serv(&me)->timestamp)
1325 cli_serv(&me)->timestamp = start_timestamp;
1326 if (IsUnknown(cptr))
1327 cli_serv(cptr)->timestamp = TStime();
1329 if (start_timestamp < cli_serv(&me)->timestamp) {
1330 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1331 "%Tu < %Tu", start_timestamp,
1332 cli_serv(&me)->timestamp);
1333 cli_serv(&me)->timestamp = start_timestamp;
1334 TSoffset += timestamp - recv_time;
1335 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1336 (int)(timestamp - recv_time));
1337 } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
1339 cli_serv(cptr)->timestamp = TStime();
1341 else if (timestamp != recv_time) {
1343 * Equal start times, we have a collision. Let the connected-to
1344 * server decide. This assumes leafs issue more than half of the
1345 * connection attempts.
1347 if (IsUnknown(cptr))
1348 cli_serv(cptr)->timestamp = TStime();
1349 else if (IsHandshake(cptr)) {
1350 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1351 (int)(timestamp - recv_time));
1352 TSoffset += timestamp - recv_time;
1358 ret = server_estab(cptr, aconf);
1363 if (feature_bool(FEAT_RELIABLE_CLOCK) &&
1364 abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
1365 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1366 "timestamp-clock difference of %Td seconds! Used "
1367 "SETTIME to correct this.", timestamp - recv_time);
1368 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
1379 * parv[0] = sender prefix
1380 * parv[1] = servername
1381 * parv[2] = hopcount
1382 * parv[3] = start timestamp
1383 * parv[4] = link timestamp
1384 * parv[5] = major protocol version: P09/P10
1385 * parv[parc-1] = serverinfo
1387 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1388 * numeric nick mask of this server.
1389 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1391 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1395 char info[REALLEN + 1];
1397 struct Client* acptr;
1398 struct Client* bcptr;
1399 struct Client* LHcptr = 0;
1400 struct ConfItem* aconf = 0;
1401 struct ConfItem* lhconf = 0;
1402 struct Jupe* ajupe = 0;
1405 int active_lh_line = 0;
1406 unsigned short prot;
1407 time_t start_timestamp;
1408 time_t timestamp = 0;
1414 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1418 if (IsUserPort(cptr))
1419 return exit_client_msg(cptr, cptr, &me,
1420 "You cannot connect a server to a user port; connect to %s port %u",
1421 me.name, server_port);
1423 recv_time = TStime();
1427 return need_more_params(sptr, "SERVER");
1428 return exit_client(cptr, cptr, &me, "Need more parameters");
1434 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1435 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1437 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1440 prot = atoi(parv[5] + 1);
1441 if (prot > atoi(MAJOR_PROTOCOL))
1442 prot = atoi(MAJOR_PROTOCOL);
1444 * Because the previous test is only in 2.10, the following is needed
1445 * till all servers are 2.10:
1447 if (IsServer(cptr) && prot > Protocol(cptr))
1448 prot = Protocol(cptr);
1449 hop = atoi(parv[2]);
1450 start_timestamp = atoi(parv[3]);
1451 timestamp = atoi(parv[4]);
1452 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1453 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1454 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1456 return exit_client_msg(cptr, sptr, &me,
1457 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1459 ircd_strncpy(info, parv[parc - 1], REALLEN);
1460 info[REALLEN] = '\0';
1461 if (prot < atoi(MINOR_PROTOCOL)) {
1462 sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1463 parv[5], cptr->name);
1464 return exit_new_server(cptr, sptr, host, timestamp,
1465 "Incompatible protocol: %s", parv[5]);
1468 * Check for "FRENCH " infection ;-) (actually this should
1469 * be replaced with routine to check the hostname syntax in
1470 * general). [ This check is still needed, even after the parse
1471 * is fixed, because someone can send "SERVER :foo bar " ].
1472 * Also, changed to check other "difficult" characters, now
1473 * that parse lets all through... --msa
1475 if (strlen(host) > HOSTLEN)
1476 host[HOSTLEN] = '\0';
1477 for (ch = host; *ch; ch++)
1478 if (*ch <= ' ' || *ch > '~')
1480 if (*ch || !strchr(host, '.'))
1482 sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1483 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1489 * A local server introduces a new server behind this link.
1490 * Check if this is allowed according L:, H: and Q: lines.
1492 if (info[0] == '\0')
1493 return exit_client_msg(cptr, cptr, &me,
1494 "No server info specified for %s", host);
1496 * See if the newly found server is behind a guaranteed
1497 * leaf (L-line). If so, close the link.
1499 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1500 (!lhconf->port || (hop > lhconf->port)))
1503 * L: lines normally come in pairs, here we try to
1504 * make sure that the oldest link is squitted, not
1508 if (timestamp <= cptr->serv->timestamp)
1509 LHcptr = 0; /* Kill incoming server */
1511 LHcptr = cptr; /* Squit ourselfs */
1513 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1514 (lhconf->port && (hop > lhconf->port)))
1516 struct Client *ac3ptr;
1518 /* Look for net junction causing this: */
1519 LHcptr = 0; /* incoming server */
1520 if (*parv[5] != 'J') {
1521 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1522 if (IsJunction(ac3ptr)) {
1531 if (IsUnknown(cptr) || IsHandshake(cptr))
1536 * A local link that is still in undefined state wants
1537 * to be a SERVER. Check if this is allowed and change
1538 * status accordingly...
1541 * If there is more then one server on the same machine
1542 * that we try to connect to, it could be that the /CONNECT
1543 * <mask> caused this connect to be put at the wrong place
1544 * in the hashtable. --Run
1545 * Same thing for Unknown connections that first send NICK.
1547 * Better check if the two strings are (caseless) identical
1548 * and not mess with hash internals.
1551 if ((!(EmptyString(cptr->name)))
1552 && (IsUnknown(cptr) || IsHandshake(cptr))
1553 && 0 != ircd_strcmp(cptr->name, host))
1554 hChangeClient(cptr, host);
1555 ircd_strncpy(cptr->name, host, HOSTLEN);
1556 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1557 cptr->hopcount = hop;
1559 /* check connection rules */
1560 if (0 != conf_eval_crule(host, CRULE_ALL)) {
1561 ServerStats->is_ref++;
1562 sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1563 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1565 if (conf_check_server(cptr)) {
1566 ++ServerStats->is_ref;
1567 sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1568 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1575 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1576 ++ServerStats->is_ref;
1578 sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1579 return exit_client_msg(cptr, cptr, &me,
1580 "Access denied. No conf line for server %s", cptr->name);
1582 sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1584 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1586 sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1587 "\"general.undernet.org\"", cptr->name);
1588 return exit_client_msg(cptr, cptr, &me,
1589 "No C/N lines for server %s", cptr->name);
1591 #endif /* GODMODE */
1593 #ifdef CRYPT_LINK_PASSWORD
1594 /* passwd may be NULL. Head it off at the pass... */
1597 encr = ircd_crypt(cptr->passwd, aconf->passwd);
1602 encr = cptr->passwd;
1603 #endif /* CRYPT_LINK_PASSWORD */
1605 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1606 ++ServerStats->is_ref;
1607 sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1608 return exit_client_msg(cptr, cptr, &me,
1609 "No Access (passwd mismatch) %s", cptr->name);
1611 #endif /* not GODMODE */
1612 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1615 for (i = 0; i <= HighestFd; i++)
1616 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1625 * We want to find IsConnecting() and IsHandshake() too,
1627 * The second finds collisions with numeric representation of existing
1628 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1631 while ((acptr = FindClient(host)) ||
1632 (parc > 7 && (acptr = FindNServer(parv[6]))))
1635 * This link is trying feed me a server that I already have
1636 * access through another path
1638 * Do not allow Uworld to do this.
1639 * Do not allow servers that are juped.
1640 * Do not allow servers that have older link timestamps
1642 * Do not allow servers that use the same numeric as an existing
1643 * server, but have a different name.
1645 * If my ircd.conf sucks, I can try to connect to myself:
1648 return exit_client_msg(cptr, cptr, &me,
1649 "nick collision with me, check server number in M:? (%s)", host);
1651 * Detect wrong numeric.
1653 if (0 != ircd_strcmp(acptr->name, host))
1655 sendto_serv_butone(cptr, /* XXX DEAD */
1656 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1657 me.name, acptr->name, host);
1658 return exit_client_msg(cptr, cptr, &me,
1659 "NUMERIC collision between %s and %s."
1660 " Is your server numeric correct ?", host, acptr->name);
1663 * Kill our try, if we had one.
1665 if (IsConnecting(acptr))
1667 if (!active_lh_line && exit_client(cptr, acptr, &me,
1668 "Just connected via another link") == CPTR_KILLED)
1671 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1672 * 'IsServer', because new 'IsConnecting's are refused to
1673 * the same server if we already had it.
1678 * Avoid other nick collisions...
1679 * This is a doubtfull test though, what else would it be
1680 * when it has a server.name ?
1682 else if (!IsServer(acptr) && !IsHandshake(acptr))
1683 return exit_client_msg(cptr, cptr, &me,
1684 "Nickname %s already exists!", host);
1686 * Our new server might be a juped server,
1687 * or someone trying abuse a second Uworld:
1689 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1690 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1692 if (!IsServer(sptr))
1693 return exit_client(cptr, sptr, &me, acptr->info);
1694 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1695 me.name, parv[0], parv[1], cptr->name);
1696 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1699 * Of course we find the handshake this link was before :)
1701 else if (IsHandshake(acptr) && acptr == cptr)
1704 * Here we have a server nick collision...
1705 * We don't want to kill the link that was last /connected,
1706 * but we neither want to kill a good (old) link.
1707 * Therefor we kill the second youngest link.
1711 struct Client* c2ptr = 0;
1712 struct Client* c3ptr = acptr;
1713 struct Client* ac2ptr;
1714 struct Client* ac3ptr;
1716 /* Search youngest link: */
1717 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1718 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1722 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1723 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1726 if (timestamp > c3ptr->serv->timestamp)
1729 c2ptr = acptr; /* Make sure they differ */
1731 /* Search second youngest link: */
1732 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1733 if (ac2ptr != c3ptr &&
1734 ac2ptr->serv->timestamp >
1735 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1739 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1740 if (ac2ptr != c3ptr &&
1741 ac2ptr->serv->timestamp >
1742 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1745 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1747 /* If timestamps are equal, decide which link to break
1750 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1751 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1760 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1765 n2up = IsServer(sptr) ? sptr->name : me.name;
1770 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1775 n3up = IsServer(sptr) ? sptr->name : me.name;
1777 if (strcmp(n2, n2up) > 0)
1779 if (strcmp(n3, n3up) > 0)
1781 if (strcmp(n3, n2) > 0)
1788 /* Now squit the second youngest link: */
1790 return exit_new_server(cptr, sptr, host, timestamp,
1791 "server %s already exists and is %ld seconds younger.",
1792 host, (long)acptr->serv->timestamp - (long)timestamp);
1793 else if (c2ptr->from == cptr || IsServer(sptr))
1795 struct Client *killedptrfrom = c2ptr->from;
1799 * If the L: or H: line also gets rid of this link,
1800 * we sent just one squit.
1802 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1805 * If breaking the loop here solves the L: or H:
1806 * line problem, we don't squit that.
1808 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1813 * If we still have a L: or H: line problem,
1814 * we prefer to squit the new server, solving
1815 * loop and L:/H: line problem with only one squit.
1822 * If the new server was introduced by a server that caused a
1823 * Ghost less then 20 seconds ago, this is probably also
1824 * a Ghost... (20 seconds is more then enough because all
1825 * SERVER messages are at the beginning of a net.burst). --Run
1827 if (CurrentTime - cptr->serv->ghost < 20)
1829 killedptrfrom = acptr->from;
1830 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1833 else if (exit_client_msg(cptr, c2ptr, &me,
1834 "Loop <-- %s (new link is %ld seconds younger)", host,
1835 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1836 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1839 * Did we kill the incoming server off already ?
1841 if (killedptrfrom == cptr)
1848 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1850 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1859 * We can't believe it is a lagged server message
1860 * when it directly connects to us...
1861 * kill the older link at the ghost, rather then
1862 * at the second youngest link, assuming it isn't
1865 ghost = CurrentTime; /* Mark that it caused a ghost */
1866 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1876 return exit_new_server(cptr, sptr, host, timestamp,
1877 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1879 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1883 int killed = a_kills_b_too(LHcptr, sptr);
1884 if (active_lh_line < 3)
1886 if (exit_client_msg(cptr, LHcptr, &me,
1887 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1889 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1894 ServerStats->is_ref++;
1895 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1899 * Did we kill the incoming server off already ?
1909 * Server is informing about a new server behind
1910 * this link. Create REMOTE server structure,
1911 * add it to list and propagate word to my other
1915 acptr = make_client(cptr, STAT_SERVER);
1917 acptr->serv->prot = prot;
1918 acptr->serv->timestamp = timestamp;
1919 acptr->hopcount = hop;
1920 ircd_strncpy(acptr->name, host, HOSTLEN);
1921 ircd_strncpy(acptr->info, info, REALLEN);
1922 acptr->serv->up = sptr;
1923 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1924 /* Use cptr, because we do protocol 9 -> 10 translation
1925 for numeric nicks ! */
1926 SetServerYXX(cptr, acptr, parv[6]);
1928 Count_newremoteserver(UserStats);
1929 if (Protocol(acptr) < 10)
1930 acptr->flags |= FLAGS_TS8;
1931 add_client_to_list(acptr);
1933 if (*parv[5] == 'J')
1936 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
1937 sptr->name, acptr->name);
1941 * Old sendto_serv_but_one() call removed because we now need to send
1942 * different names to different servers (domain name matching).
1944 for (i = 0; i <= HighestFd; i++)
1946 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1947 bcptr == cptr || IsMe(bcptr))
1949 if (0 == match(me.name, acptr->name))
1951 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
1952 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1953 NumServCap(acptr), acptr->info);
1958 if (IsUnknown(cptr) || IsHandshake(cptr))
1961 cptr->serv->timestamp = timestamp;
1962 cptr->serv->prot = prot;
1963 cptr->serv->ghost = ghost;
1964 SetServerYXX(cptr, cptr, parv[6]);
1965 if (start_timestamp > OLDEST_TS)
1967 #ifndef RELIABLE_CLOCK
1969 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
1970 TIME_T_FMT, me.serv->timestamp, start_timestamp);
1971 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
1972 TIME_T_FMT " ; difference %ld",
1973 recv_time, timestamp, timestamp - recv_time);
1975 if (start_timestamp < me.serv->timestamp)
1977 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
1978 start_timestamp, me.serv->timestamp);
1979 me.serv->timestamp = start_timestamp;
1980 TSoffset += timestamp - recv_time;
1981 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
1983 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1984 cptr->serv->timestamp = TStime();
1986 else if (timestamp != recv_time)
1989 * Equal start times, we have a collision. Let the connected-to server
1990 * decide. This assumes leafs issue more than half of the connection
1993 if (IsUnknown(cptr))
1994 cptr->serv->timestamp = TStime();
1995 else if (IsHandshake(cptr))
1997 sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
1998 (int)(timestamp - recv_time));
1999 TSoffset += timestamp - recv_time;
2002 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2003 if (start_timestamp < me.serv->timestamp)
2004 me.serv->timestamp = start_timestamp;
2005 if (IsUnknown(cptr))
2006 cptr->serv->timestamp = TStime();
2010 ret = server_estab(cptr, aconf); /* XXX DEAD */
2014 #ifdef RELIABLE_CLOCK
2015 if (abs(cptr->serv->timestamp - recv_time) > 30)
2017 sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2018 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2019 " this.", timestamp - recv_time);
2020 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2021 me.name, TStime(), me.name);