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
95 #include "ircd_reply.h"
96 #include "ircd_string.h"
101 #include "numnicks.h"
102 #include "querycmds.h"
109 #include "userload.h"
116 * mr_server - registration message handler
118 * parv[0] = sender prefix
119 * parv[1] = servername
121 * parv[3] = start timestamp
122 * parv[4] = link timestamp
123 * parv[5] = major protocol version: P09/P10
124 * parv[parc-1] = serverinfo
126 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
127 * numeric nick mask of this server.
128 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
130 int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
134 char info[REALLEN + 1];
136 struct Client* acptr;
137 struct Client* bcptr;
138 struct Client* LHcptr = 0;
139 struct ConfItem* aconf = 0;
140 struct ConfItem* cconf;
141 struct ConfItem* lhconf = 0;
144 int active_lh_line = 0;
146 time_t start_timestamp;
147 time_t timestamp = 0;
153 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
157 if (IsUserPort(cptr))
158 return exit_client_msg(cptr, cptr, &me,
159 "Cannot connect a server to a user port");
161 recv_time = TStime();
166 return need_more_params(sptr, "SERVER");
167 return exit_client(cptr, cptr, &me, "Need more parameters");
169 ircd_log(L_NOTICE, "SERVER: %s %s[%s]", parv[1], cptr->sockhost, cptr->sock_ip);
174 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
175 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
177 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
180 prot = atoi(parv[5] + 1);
181 if (prot > atoi(MAJOR_PROTOCOL))
182 prot = atoi(MAJOR_PROTOCOL);
184 * Because the previous test is only in 2.10, the following is needed
185 * till all servers are 2.10:
187 if (IsServer(cptr) && prot > Protocol(cptr))
188 prot = Protocol(cptr);
190 start_timestamp = atoi(parv[3]);
191 timestamp = atoi(parv[4]);
192 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
193 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
195 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
197 return exit_client_msg(cptr, sptr, &me,
198 "Bogus timestamps (%s %s)", parv[3], parv[4]);
200 ircd_strncpy(info, parv[parc - 1], REALLEN);
201 info[REALLEN] = '\0';
202 if (prot < atoi(MINOR_PROTOCOL)) {
203 sendto_ops("Got incompatible protocol version (%s) from %s",
204 parv[5], cptr->name);
205 return exit_new_server(cptr, sptr, host, timestamp,
206 "Incompatible protocol: %s", parv[5]);
209 * Check for "FRENCH " infection ;-) (actually this should
210 * be replaced with routine to check the hostname syntax in
211 * general). [ This check is still needed, even after the parse
212 * is fixed, because someone can send "SERVER :foo bar " ].
213 * Also, changed to check other "difficult" characters, now
214 * that parse lets all through... --msa
216 if (strlen(host) > HOSTLEN)
217 host[HOSTLEN] = '\0';
219 for (ch = host; *ch; ch++) {
220 if (*ch <= ' ' || *ch > '~')
223 if (*ch || !strchr(host, '.')) {
224 sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
225 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
231 * A local server introduces a new server behind this link.
232 * Check if this is allowed according L:, H: and Q: lines.
235 return exit_client_msg(cptr, cptr, &me,
236 "No server info specified for %s", host);
238 * See if the newly found server is behind a guaranteed
239 * leaf (L-line). If so, close the link.
241 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
242 (!lhconf->port || (hop > lhconf->port)))
245 * L: lines normally come in pairs, here we try to
246 * make sure that the oldest link is squitted, not
250 if (timestamp <= cptr->serv->timestamp)
251 LHcptr = 0; /* Kill incoming server */
253 LHcptr = cptr; /* Squit ourselfs */
255 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
256 (lhconf->port && (hop > lhconf->port)))
258 struct Client *ac3ptr;
260 /* Look for net junction causing this: */
261 LHcptr = 0; /* incoming server */
262 if (*parv[5] != 'J') {
263 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
264 if (IsJunction(ac3ptr)) {
273 if (IsUnknown(cptr) || IsHandshake(cptr))
278 * A local link that is still in undefined state wants
279 * to be a SERVER. Check if this is allowed and change
280 * status accordingly...
283 * If there is more then one server on the same machine
284 * that we try to connect to, it could be that the /CONNECT
285 * <mask> caused this connect to be put at the wrong place
286 * in the hashtable. --Run
287 * Same thing for Unknown connections that first send NICK.
289 * Better check if the two strings are (caseless) identical
290 * and not mess with hash internals.
293 if (!EmptyString(cptr->name) &&
294 (IsUnknown(cptr) || IsHandshake(cptr)) &&
295 0 != ircd_strcmp(cptr->name, host))
296 hChangeClient(cptr, host);
297 ircd_strncpy(cptr->name, host, HOSTLEN);
298 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
299 cptr->hopcount = hop;
301 /* check connection rules */
302 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
303 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
304 if (crule_eval(cconf->passwd)) {
305 ServerStats->is_ref++;
306 sendto_ops("Refused connection from %s.", cptr->name);
307 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
311 if (conf_check_server(cptr)) {
312 ++ServerStats->is_ref;
313 sendto_ops("Received unauthorized connection from %s.", cptr->name);
314 return exit_client(cptr, cptr, &me, "No C:line");
321 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
322 ++ServerStats->is_ref;
324 sendto_ops("Access denied. No conf line for server %s", cptr->name);
325 return exit_client_msg(cptr, cptr, &me,
326 "Access denied. No conf line for server %s", cptr->name);
328 sendto_ops("General C: line active: No line for server %s", cptr->name);
329 aconf = find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
331 sendto_ops("Neither C lines for server %s nor "
332 "\"general.undernet.org\"", cptr->name);
333 return exit_client_msg(cptr, cptr, &me, "No C lines for server %s", cptr->name);
337 #ifdef CRYPT_LINK_PASSWORD
338 /* passwd may be NULL. Head it off at the pass... */
342 salt[0] = aconf->passwd[0];
343 salt[1] = aconf->passwd[1];
345 encr = ircd_crypt(cptr->passwd, salt);
351 #endif /* CRYPT_LINK_PASSWORD */
353 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
354 ++ServerStats->is_ref;
355 sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
356 return exit_client_msg(cptr, cptr, &me,
357 "No Access (passwd mismatch) %s", cptr->name);
359 #endif /* not GODMODE */
360 memset(cptr->passwd, 0, sizeof(cptr->passwd));
363 for (i = 0; i <= HighestFd; i++)
364 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
373 * We want to find IsConnecting() and IsHandshake() too,
375 * The second finds collisions with numeric representation of existing
376 * servers - these shouldn't happen anymore when all upgraded to 2.10.
379 while ((acptr = FindClient(host)) ||
380 (parc > 7 && (acptr = FindNServer(parv[6]))))
383 * This link is trying feed me a server that I already have
384 * access through another path
386 * Do not allow Uworld to do this.
387 * Do not allow servers that are juped.
388 * Do not allow servers that have older link timestamps
390 * Do not allow servers that use the same numeric as an existing
391 * server, but have a different name.
393 * If my ircd.conf sucks, I can try to connect to myself:
396 return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s)", host);
398 * Detect wrong numeric.
400 if (0 != ircd_strcmp(acptr->name, host)) {
401 sendto_serv_butone(cptr,
402 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
403 me.name, acptr->name, host);
404 return exit_client_msg(cptr, cptr, &me,
405 "NUMERIC collision between %s and %s."
406 " Is your server numeric correct ?", host, acptr->name);
409 * Kill our try, if we had one.
411 if (IsConnecting(acptr))
413 if (!active_lh_line && exit_client(cptr, acptr, &me,
414 "Just connected via another link") == CPTR_KILLED)
417 * We can have only ONE 'IsConnecting', 'IsHandshake' or
418 * 'IsServer', because new 'IsConnecting's are refused to
419 * the same server if we already had it.
424 * Avoid other nick collisions...
425 * This is a doubtfull test though, what else would it be
426 * when it has a server.name ?
428 else if (!IsServer(acptr) && !IsHandshake(acptr))
429 return exit_client_msg(cptr, cptr, &me,
430 "Nickname %s already exists!", host);
432 * Our new server might be a juped server,
433 * or someone trying abuse a second Uworld:
435 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
436 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
439 return exit_client(cptr, sptr, &me, acptr->info);
440 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
441 me.name, parv[0], parv[1], cptr->name);
442 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
445 * Of course we find the handshake this link was before :)
447 else if (IsHandshake(acptr) && acptr == cptr)
450 * Here we have a server nick collision...
451 * We don't want to kill the link that was last /connected,
452 * but we neither want to kill a good (old) link.
453 * Therefor we kill the second youngest link.
457 struct Client* c2ptr = 0;
458 struct Client* c3ptr = acptr;
459 struct Client* ac2ptr;
460 struct Client* ac3ptr;
462 /* Search youngest link: */
463 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
464 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
468 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
469 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
472 if (timestamp > c3ptr->serv->timestamp)
475 c2ptr = acptr; /* Make sure they differ */
477 /* Search second youngest link: */
478 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
479 if (ac2ptr != c3ptr &&
480 ac2ptr->serv->timestamp >
481 (c2ptr ? c2ptr->serv->timestamp : timestamp))
485 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
486 if (ac2ptr != c3ptr &&
487 ac2ptr->serv->timestamp >
488 (c2ptr ? c2ptr->serv->timestamp : timestamp))
491 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
493 /* If timestamps are equal, decide which link to break
496 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
497 (c3ptr ? c3ptr->serv->timestamp : timestamp))
506 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
511 n2up = IsServer(sptr) ? sptr->name : me.name;
516 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
521 n3up = IsServer(sptr) ? sptr->name : me.name;
523 if (strcmp(n2, n2up) > 0)
525 if (strcmp(n3, n3up) > 0)
527 if (strcmp(n3, n2) > 0)
534 /* Now squit the second youngest link: */
536 return exit_new_server(cptr, sptr, host, timestamp,
537 "server %s already exists and is %ld seconds younger.",
538 host, (long)acptr->serv->timestamp - (long)timestamp);
539 else if (c2ptr->from == cptr || IsServer(sptr))
541 struct Client *killedptrfrom = c2ptr->from;
545 * If the L: or H: line also gets rid of this link,
546 * we sent just one squit.
548 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
551 * If breaking the loop here solves the L: or H:
552 * line problem, we don't squit that.
554 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
559 * If we still have a L: or H: line problem,
560 * we prefer to squit the new server, solving
561 * loop and L:/H: line problem with only one squit.
568 * If the new server was introduced by a server that caused a
569 * Ghost less then 20 seconds ago, this is probably also
570 * a Ghost... (20 seconds is more then enough because all
571 * SERVER messages are at the beginning of a net.burst). --Run
573 if (CurrentTime - cptr->serv->ghost < 20)
575 killedptrfrom = acptr->from;
576 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
579 else if (exit_client_msg(cptr, c2ptr, &me,
580 "Loop <-- %s (new link is %ld seconds younger)", host,
581 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
582 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
585 * Did we kill the incoming server off already ?
587 if (killedptrfrom == cptr)
594 if (LHcptr && a_kills_b_too(LHcptr, acptr))
596 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
605 * We can't believe it is a lagged server message
606 * when it directly connects to us...
607 * kill the older link at the ghost, rather then
608 * at the second youngest link, assuming it isn't
611 ghost = CurrentTime; /* Mark that it caused a ghost */
612 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
622 return exit_new_server(cptr, sptr, host, timestamp,
623 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
625 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
629 int killed = a_kills_b_too(LHcptr, sptr);
630 if (active_lh_line < 3)
632 if (exit_client_msg(cptr, LHcptr, &me,
633 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
635 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
640 ServerStats->is_ref++;
641 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
645 * Did we kill the incoming server off already ?
655 * Server is informing about a new server behind
656 * this link. Create REMOTE server structure,
657 * add it to list and propagate word to my other
661 acptr = make_client(cptr, STAT_SERVER);
663 acptr->serv->prot = prot;
664 acptr->serv->timestamp = timestamp;
665 acptr->hopcount = hop;
666 ircd_strncpy(acptr->name, host, HOSTLEN);
667 ircd_strncpy(acptr->info, info, REALLEN);
668 acptr->serv->up = sptr;
669 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
670 /* Use cptr, because we do protocol 9 -> 10 translation
671 for numeric nicks ! */
672 SetServerYXX(cptr, acptr, parv[6]);
674 Count_newremoteserver(UserStats);
675 if (Protocol(acptr) < 10)
676 acptr->flags |= FLAGS_TS8;
677 add_client_to_list(acptr);
682 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
683 sptr->name, acptr->name);
687 * Old sendto_serv_but_one() call removed because we now need to send
688 * different names to different servers (domain name matching).
690 for (i = 0; i <= HighestFd; i++)
692 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
693 bcptr == cptr || IsMe(bcptr))
695 if (0 == match(me.name, acptr->name))
697 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
698 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
699 NumServCap(acptr), acptr->info);
704 if (IsUnknown(cptr) || IsHandshake(cptr))
707 cptr->serv->timestamp = timestamp;
708 cptr->serv->prot = prot;
709 cptr->serv->ghost = ghost;
710 SetServerYXX(cptr, cptr, parv[6]);
711 if (start_timestamp > OLDEST_TS)
713 #ifndef RELIABLE_CLOCK
715 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
716 TIME_T_FMT, me.serv->timestamp, start_timestamp);
717 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
718 TIME_T_FMT " ; difference %ld",
719 recv_time, timestamp, timestamp - recv_time);
721 if (start_timestamp < me.serv->timestamp)
723 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
724 start_timestamp, me.serv->timestamp);
725 me.serv->timestamp = start_timestamp;
726 TSoffset += timestamp - recv_time;
727 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
729 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
730 cptr->serv->timestamp = TStime();
732 else if (timestamp != recv_time)
735 * Equal start times, we have a collision. Let the connected-to server
736 * decide. This assumes leafs issue more than half of the connection
740 cptr->serv->timestamp = TStime();
741 else if (IsHandshake(cptr))
743 sendto_ops("clock adjusted by adding %d",
744 (int)(timestamp - recv_time));
745 TSoffset += timestamp - recv_time;
748 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
749 if (start_timestamp < me.serv->timestamp)
750 me.serv->timestamp = start_timestamp;
752 cptr->serv->timestamp = TStime();
756 ret = server_estab(cptr, aconf);
760 #ifdef RELIABLE_CLOCK
761 if (abs(cptr->serv->timestamp - recv_time) > 30)
763 sendto_ops("Connected to a net with a timestamp-clock"
764 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
765 " this.", timestamp - recv_time);
766 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
767 me.name, TStime(), me.name);
775 * ms_server - server message handler
777 * parv[0] = sender prefix
778 * parv[1] = servername
780 * parv[3] = start timestamp
781 * parv[4] = link timestamp
782 * parv[5] = major protocol version: P09/P10
783 * parv[parc-1] = serverinfo
785 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
786 * numeric nick mask of this server.
787 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
789 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
793 char info[REALLEN + 1];
795 struct Client* acptr;
796 struct Client* bcptr;
797 struct Client* LHcptr = 0;
798 struct ConfItem* aconf = 0;
799 struct ConfItem* cconf;
800 struct ConfItem* lhconf = 0;
803 int active_lh_line = 0;
805 time_t start_timestamp;
806 time_t timestamp = 0;
812 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
816 if (IsUserPort(cptr))
817 return exit_client_msg(cptr, cptr, &me,
818 "Cannot connect a server to a user port");
820 recv_time = TStime();
824 return need_more_params(sptr, "SERVER");
825 return exit_client(cptr, cptr, &me, "Need more parameters");
831 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
832 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
834 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
837 prot = atoi(parv[5] + 1);
838 if (prot > atoi(MAJOR_PROTOCOL))
839 prot = atoi(MAJOR_PROTOCOL);
841 * Because the previous test is only in 2.10, the following is needed
842 * till all servers are 2.10:
844 if (IsServer(cptr) && prot > Protocol(cptr))
845 prot = Protocol(cptr);
847 start_timestamp = atoi(parv[3]);
848 timestamp = atoi(parv[4]);
849 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
850 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
851 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
853 return exit_client_msg(cptr, sptr, &me,
854 "Bogus timestamps (%s %s)", parv[3], parv[4]);
856 ircd_strncpy(info, parv[parc - 1], REALLEN);
857 info[REALLEN] = '\0';
858 if (prot < atoi(MINOR_PROTOCOL)) {
859 sendto_ops("Got incompatible protocol version (%s) from %s",
860 parv[5], cptr->name);
861 return exit_new_server(cptr, sptr, host, timestamp,
862 "Incompatible protocol: %s", parv[5]);
865 * Check for "FRENCH " infection ;-) (actually this should
866 * be replaced with routine to check the hostname syntax in
867 * general). [ This check is still needed, even after the parse
868 * is fixed, because someone can send "SERVER :foo bar " ].
869 * Also, changed to check other "difficult" characters, now
870 * that parse lets all through... --msa
872 if (strlen(host) > HOSTLEN)
873 host[HOSTLEN] = '\0';
874 for (ch = host; *ch; ch++)
875 if (*ch <= ' ' || *ch > '~')
877 if (*ch || !strchr(host, '.')) {
878 sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
879 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
885 * A local server introduces a new server behind this link.
886 * Check if this is allowed according L:, H: and Q: lines.
889 return exit_client_msg(cptr, cptr, &me,
890 "No server info specified for %s", host);
892 * See if the newly found server is behind a guaranteed
893 * leaf (L-line). If so, close the link.
895 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
896 (!lhconf->port || (hop > lhconf->port)))
899 * L: lines normally come in pairs, here we try to
900 * make sure that the oldest link is squitted, not
904 if (timestamp <= cptr->serv->timestamp)
905 LHcptr = 0; /* Kill incoming server */
907 LHcptr = cptr; /* Squit ourselfs */
909 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
910 (lhconf->port && (hop > lhconf->port)))
912 struct Client *ac3ptr;
914 /* Look for net junction causing this: */
915 LHcptr = 0; /* incoming server */
916 if (*parv[5] != 'J') {
917 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
918 if (IsJunction(ac3ptr)) {
927 if (IsUnknown(cptr) || IsHandshake(cptr))
932 * A local link that is still in undefined state wants
933 * to be a SERVER. Check if this is allowed and change
934 * status accordingly...
937 * If there is more then one server on the same machine
938 * that we try to connect to, it could be that the /CONNECT
939 * <mask> caused this connect to be put at the wrong place
940 * in the hashtable. --Run
941 * Same thing for Unknown connections that first send NICK.
943 * Better check if the two strings are (caseless) identical
944 * and not mess with hash internals.
947 if ((!(EmptyString(cptr->name)))
948 && (IsUnknown(cptr) || IsHandshake(cptr))
949 && 0 != ircd_strcmp(cptr->name, host))
950 hChangeClient(cptr, host);
951 ircd_strncpy(cptr->name, host, HOSTLEN);
952 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
953 cptr->hopcount = hop;
955 /* check connection rules */
956 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
957 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
958 if (crule_eval(cconf->passwd))
960 ServerStats->is_ref++;
961 sendto_ops("Refused connection from %s.", cptr->name);
962 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
966 if (conf_check_server(cptr)) {
967 ++ServerStats->is_ref;
968 sendto_ops("Received unauthorized connection from %s.", cptr->name);
969 return exit_client(cptr, cptr, &me, "No C conf lines");
976 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
977 ++ServerStats->is_ref;
979 sendto_ops("Access denied. No conf line for server %s", cptr->name);
980 return exit_client_msg(cptr, cptr, &me,
981 "Access denied. No conf line for server %s", cptr->name);
983 sendto_ops("General C line active: No line for server %s", cptr->name);
985 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
987 sendto_ops("Neither C lines for server %s nor "
988 "\"general.undernet.org\"", cptr->name);
989 return exit_client_msg(cptr, cptr, &me,
990 "No C lines for server %s", cptr->name);
994 #ifdef CRYPT_LINK_PASSWORD
995 /* passwd may be NULL. Head it off at the pass... */
1000 salt[0] = aconf->passwd[0];
1001 salt[1] = aconf->passwd[1];
1003 encr = ircd_crypt(cptr->passwd, salt);
1008 encr = cptr->passwd;
1009 #endif /* CRYPT_LINK_PASSWORD */
1011 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1012 ++ServerStats->is_ref;
1013 sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
1014 return exit_client_msg(cptr, cptr, &me,
1015 "No Access (passwd mismatch) %s", cptr->name);
1017 #endif /* not GODMODE */
1018 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1021 for (i = 0; i <= HighestFd; i++)
1022 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1031 * We want to find IsConnecting() and IsHandshake() too,
1033 * The second finds collisions with numeric representation of existing
1034 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1037 while ((acptr = FindClient(host)) ||
1038 (parc > 7 && (acptr = FindNServer(parv[6]))))
1041 * This link is trying feed me a server that I already have
1042 * access through another path
1044 * Do not allow Uworld to do this.
1045 * Do not allow servers that are juped.
1046 * Do not allow servers that have older link timestamps
1048 * Do not allow servers that use the same numeric as an existing
1049 * server, but have a different name.
1051 * If my ircd.conf sucks, I can try to connect to myself:
1054 return exit_client_msg(cptr, cptr, &me,
1055 "nick collision with me (%s)", host);
1057 * Detect wrong numeric.
1059 if (0 != ircd_strcmp(acptr->name, host))
1061 sendto_serv_butone(cptr,
1062 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1063 me.name, acptr->name, host);
1064 return exit_client_msg(cptr, cptr, &me,
1065 "NUMERIC collision between %s and %s."
1066 " Is your server numeric correct ?", host, acptr->name);
1069 * Kill our try, if we had one.
1071 if (IsConnecting(acptr))
1073 if (!active_lh_line && exit_client(cptr, acptr, &me,
1074 "Just connected via another link") == CPTR_KILLED)
1077 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1078 * 'IsServer', because new 'IsConnecting's are refused to
1079 * the same server if we already had it.
1084 * Avoid other nick collisions...
1085 * This is a doubtfull test though, what else would it be
1086 * when it has a server.name ?
1088 else if (!IsServer(acptr) && !IsHandshake(acptr))
1089 return exit_client_msg(cptr, cptr, &me,
1090 "Nickname %s already exists!", host);
1092 * Our new server might be a juped server,
1093 * or someone trying abuse a second Uworld:
1095 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1096 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1098 if (!IsServer(sptr))
1099 return exit_client(cptr, sptr, &me, acptr->info);
1100 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
1101 me.name, parv[0], parv[1], cptr->name);
1102 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1105 * Of course we find the handshake this link was before :)
1107 else if (IsHandshake(acptr) && acptr == cptr)
1110 * Here we have a server nick collision...
1111 * We don't want to kill the link that was last /connected,
1112 * but we neither want to kill a good (old) link.
1113 * Therefor we kill the second youngest link.
1117 struct Client* c2ptr = 0;
1118 struct Client* c3ptr = acptr;
1119 struct Client* ac2ptr;
1120 struct Client* ac3ptr;
1122 /* Search youngest link: */
1123 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1124 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1128 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1129 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1132 if (timestamp > c3ptr->serv->timestamp)
1135 c2ptr = acptr; /* Make sure they differ */
1137 /* Search second youngest link: */
1138 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1139 if (ac2ptr != c3ptr &&
1140 ac2ptr->serv->timestamp >
1141 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1145 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1146 if (ac2ptr != c3ptr &&
1147 ac2ptr->serv->timestamp >
1148 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1151 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1153 /* If timestamps are equal, decide which link to break
1156 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1157 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1166 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1171 n2up = IsServer(sptr) ? sptr->name : me.name;
1176 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1181 n3up = IsServer(sptr) ? sptr->name : me.name;
1183 if (strcmp(n2, n2up) > 0)
1185 if (strcmp(n3, n3up) > 0)
1187 if (strcmp(n3, n2) > 0)
1194 /* Now squit the second youngest link: */
1196 return exit_new_server(cptr, sptr, host, timestamp,
1197 "server %s already exists and is %ld seconds younger.",
1198 host, (long)acptr->serv->timestamp - (long)timestamp);
1199 else if (c2ptr->from == cptr || IsServer(sptr))
1201 struct Client *killedptrfrom = c2ptr->from;
1205 * If the L: or H: line also gets rid of this link,
1206 * we sent just one squit.
1208 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1211 * If breaking the loop here solves the L: or H:
1212 * line problem, we don't squit that.
1214 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1219 * If we still have a L: or H: line problem,
1220 * we prefer to squit the new server, solving
1221 * loop and L:/H: line problem with only one squit.
1228 * If the new server was introduced by a server that caused a
1229 * Ghost less then 20 seconds ago, this is probably also
1230 * a Ghost... (20 seconds is more then enough because all
1231 * SERVER messages are at the beginning of a net.burst). --Run
1233 if (CurrentTime - cptr->serv->ghost < 20)
1235 killedptrfrom = acptr->from;
1236 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1239 else if (exit_client_msg(cptr, c2ptr, &me,
1240 "Loop <-- %s (new link is %ld seconds younger)", host,
1241 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1242 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1245 * Did we kill the incoming server off already ?
1247 if (killedptrfrom == cptr)
1254 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1256 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1265 * We can't believe it is a lagged server message
1266 * when it directly connects to us...
1267 * kill the older link at the ghost, rather then
1268 * at the second youngest link, assuming it isn't
1271 ghost = CurrentTime; /* Mark that it caused a ghost */
1272 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1282 return exit_new_server(cptr, sptr, host, timestamp,
1283 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1285 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1289 int killed = a_kills_b_too(LHcptr, sptr);
1290 if (active_lh_line < 3)
1292 if (exit_client_msg(cptr, LHcptr, &me,
1293 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1295 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1300 ServerStats->is_ref++;
1301 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1305 * Did we kill the incoming server off already ?
1315 * Server is informing about a new server behind
1316 * this link. Create REMOTE server structure,
1317 * add it to list and propagate word to my other
1321 acptr = make_client(cptr, STAT_SERVER);
1323 acptr->serv->prot = prot;
1324 acptr->serv->timestamp = timestamp;
1325 acptr->hopcount = hop;
1326 ircd_strncpy(acptr->name, host, HOSTLEN);
1327 ircd_strncpy(acptr->info, info, REALLEN);
1328 acptr->serv->up = sptr;
1329 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1330 /* Use cptr, because we do protocol 9 -> 10 translation
1331 for numeric nicks ! */
1332 SetServerYXX(cptr, acptr, parv[6]);
1334 Count_newremoteserver(UserStats);
1335 if (Protocol(acptr) < 10)
1336 acptr->flags |= FLAGS_TS8;
1337 add_client_to_list(acptr);
1339 if (*parv[5] == 'J')
1342 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
1343 sptr->name, acptr->name);
1347 * Old sendto_serv_but_one() call removed because we now need to send
1348 * different names to different servers (domain name matching).
1350 for (i = 0; i <= HighestFd; i++)
1352 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1353 bcptr == cptr || IsMe(bcptr))
1355 if (0 == match(me.name, acptr->name))
1357 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
1358 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1359 NumServCap(acptr), acptr->info);
1364 if (IsUnknown(cptr) || IsHandshake(cptr))
1367 cptr->serv->timestamp = timestamp;
1368 cptr->serv->prot = prot;
1369 cptr->serv->ghost = ghost;
1370 SetServerYXX(cptr, cptr, parv[6]);
1371 if (start_timestamp > OLDEST_TS)
1373 #ifndef RELIABLE_CLOCK
1375 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
1376 TIME_T_FMT, me.serv->timestamp, start_timestamp);
1377 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
1378 TIME_T_FMT " ; difference %ld",
1379 recv_time, timestamp, timestamp - recv_time);
1381 if (start_timestamp < me.serv->timestamp)
1383 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
1384 start_timestamp, me.serv->timestamp);
1385 me.serv->timestamp = start_timestamp;
1386 TSoffset += timestamp - recv_time;
1387 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
1389 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1390 cptr->serv->timestamp = TStime();
1392 else if (timestamp != recv_time)
1395 * Equal start times, we have a collision. Let the connected-to server
1396 * decide. This assumes leafs issue more than half of the connection
1399 if (IsUnknown(cptr))
1400 cptr->serv->timestamp = TStime();
1401 else if (IsHandshake(cptr))
1403 sendto_ops("clock adjusted by adding %d",
1404 (int)(timestamp - recv_time));
1405 TSoffset += timestamp - recv_time;
1408 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
1409 if (start_timestamp < me.serv->timestamp)
1410 me.serv->timestamp = start_timestamp;
1411 if (IsUnknown(cptr))
1412 cptr->serv->timestamp = TStime();
1416 ret = server_estab(cptr, aconf);
1420 #ifdef RELIABLE_CLOCK
1421 if (abs(cptr->serv->timestamp - recv_time) > 30)
1423 sendto_ops("Connected to a net with a timestamp-clock"
1424 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
1425 " this.", timestamp - recv_time);
1426 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
1427 me.name, TStime(), me.name);
1439 * parv[0] = sender prefix
1440 * parv[1] = servername
1441 * parv[2] = hopcount
1442 * parv[3] = start timestamp
1443 * parv[4] = link timestamp
1444 * parv[5] = major protocol version: P09/P10
1445 * parv[parc-1] = serverinfo
1447 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1448 * numeric nick mask of this server.
1449 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1451 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1455 char info[REALLEN + 1];
1457 struct Client* acptr;
1458 struct Client* bcptr;
1459 struct Client* LHcptr = 0;
1460 struct ConfItem* aconf = 0;
1461 struct ConfItem* cconf;
1462 struct ConfItem* lhconf = 0;
1465 int active_lh_line = 0;
1466 unsigned short prot;
1467 time_t start_timestamp;
1468 time_t timestamp = 0;
1474 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
1478 if (IsUserPort(cptr))
1479 return exit_client_msg(cptr, cptr, &me,
1480 "You cannot connect a server to a user port; connect to %s port %u",
1481 me.name, server_port);
1483 recv_time = TStime();
1487 return need_more_params(sptr, "SERVER");
1488 return exit_client(cptr, cptr, &me, "Need more parameters");
1494 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1495 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1497 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1500 prot = atoi(parv[5] + 1);
1501 if (prot > atoi(MAJOR_PROTOCOL))
1502 prot = atoi(MAJOR_PROTOCOL);
1504 * Because the previous test is only in 2.10, the following is needed
1505 * till all servers are 2.10:
1507 if (IsServer(cptr) && prot > Protocol(cptr))
1508 prot = Protocol(cptr);
1509 hop = atoi(parv[2]);
1510 start_timestamp = atoi(parv[3]);
1511 timestamp = atoi(parv[4]);
1512 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1513 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1514 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1516 return exit_client_msg(cptr, sptr, &me,
1517 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1519 ircd_strncpy(info, parv[parc - 1], REALLEN);
1520 info[REALLEN] = '\0';
1521 if (prot < atoi(MINOR_PROTOCOL)) {
1522 sendto_ops("Got incompatible protocol version (%s) from %s",
1523 parv[5], cptr->name);
1524 return exit_new_server(cptr, sptr, host, timestamp,
1525 "Incompatible protocol: %s", parv[5]);
1528 * Check for "FRENCH " infection ;-) (actually this should
1529 * be replaced with routine to check the hostname syntax in
1530 * general). [ This check is still needed, even after the parse
1531 * is fixed, because someone can send "SERVER :foo bar " ].
1532 * Also, changed to check other "difficult" characters, now
1533 * that parse lets all through... --msa
1535 if (strlen(host) > HOSTLEN)
1536 host[HOSTLEN] = '\0';
1537 for (ch = host; *ch; ch++)
1538 if (*ch <= ' ' || *ch > '~')
1540 if (*ch || !strchr(host, '.'))
1542 sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
1543 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1549 * A local server introduces a new server behind this link.
1550 * Check if this is allowed according L:, H: and Q: lines.
1552 if (info[0] == '\0')
1553 return exit_client_msg(cptr, cptr, &me,
1554 "No server info specified for %s", host);
1556 * See if the newly found server is behind a guaranteed
1557 * leaf (L-line). If so, close the link.
1559 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1560 (!lhconf->port || (hop > lhconf->port)))
1563 * L: lines normally come in pairs, here we try to
1564 * make sure that the oldest link is squitted, not
1568 if (timestamp <= cptr->serv->timestamp)
1569 LHcptr = 0; /* Kill incoming server */
1571 LHcptr = cptr; /* Squit ourselfs */
1573 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1574 (lhconf->port && (hop > lhconf->port)))
1576 struct Client *ac3ptr;
1578 /* Look for net junction causing this: */
1579 LHcptr = 0; /* incoming server */
1580 if (*parv[5] != 'J') {
1581 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1582 if (IsJunction(ac3ptr)) {
1591 if (IsUnknown(cptr) || IsHandshake(cptr))
1596 * A local link that is still in undefined state wants
1597 * to be a SERVER. Check if this is allowed and change
1598 * status accordingly...
1601 * If there is more then one server on the same machine
1602 * that we try to connect to, it could be that the /CONNECT
1603 * <mask> caused this connect to be put at the wrong place
1604 * in the hashtable. --Run
1605 * Same thing for Unknown connections that first send NICK.
1607 * Better check if the two strings are (caseless) identical
1608 * and not mess with hash internals.
1611 if ((!(EmptyString(cptr->name)))
1612 && (IsUnknown(cptr) || IsHandshake(cptr))
1613 && 0 != ircd_strcmp(cptr->name, host))
1614 hChangeClient(cptr, host);
1615 ircd_strncpy(cptr->name, host, HOSTLEN);
1616 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1617 cptr->hopcount = hop;
1619 /* check connection rules */
1620 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
1621 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
1622 if (crule_eval(cconf->passwd))
1624 ServerStats->is_ref++;
1625 sendto_ops("Refused connection from %s.", cptr->name);
1626 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1630 if (conf_check_server(cptr)) {
1631 ++ServerStats->is_ref;
1632 sendto_ops("Received unauthorized connection from %s.", cptr->name);
1633 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1640 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1641 ++ServerStats->is_ref;
1643 sendto_ops("Access denied. No conf line for server %s", cptr->name);
1644 return exit_client_msg(cptr, cptr, &me,
1645 "Access denied. No conf line for server %s", cptr->name);
1647 sendto_ops("General C/N: line active: No line for server %s", cptr->name);
1649 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1651 sendto_ops("Neither C/N lines for server %s nor "
1652 "\"general.undernet.org\"", cptr->name);
1653 return exit_client_msg(cptr, cptr, &me,
1654 "No C/N lines for server %s", cptr->name);
1656 #endif /* GODMODE */
1658 #ifdef CRYPT_LINK_PASSWORD
1659 /* passwd may be NULL. Head it off at the pass... */
1664 salt[0] = aconf->passwd[0];
1665 salt[1] = aconf->passwd[1];
1667 encr = ircd_crypt(cptr->passwd, salt);
1672 encr = cptr->passwd;
1673 #endif /* CRYPT_LINK_PASSWORD */
1675 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1676 ++ServerStats->is_ref;
1677 sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
1678 return exit_client_msg(cptr, cptr, &me,
1679 "No Access (passwd mismatch) %s", cptr->name);
1681 #endif /* not GODMODE */
1682 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1685 for (i = 0; i <= HighestFd; i++)
1686 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1695 * We want to find IsConnecting() and IsHandshake() too,
1697 * The second finds collisions with numeric representation of existing
1698 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1701 while ((acptr = FindClient(host)) ||
1702 (parc > 7 && (acptr = FindNServer(parv[6]))))
1705 * This link is trying feed me a server that I already have
1706 * access through another path
1708 * Do not allow Uworld to do this.
1709 * Do not allow servers that are juped.
1710 * Do not allow servers that have older link timestamps
1712 * Do not allow servers that use the same numeric as an existing
1713 * server, but have a different name.
1715 * If my ircd.conf sucks, I can try to connect to myself:
1718 return exit_client_msg(cptr, cptr, &me,
1719 "nick collision with me (%s)", host);
1721 * Detect wrong numeric.
1723 if (0 != ircd_strcmp(acptr->name, host))
1725 sendto_serv_butone(cptr,
1726 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1727 me.name, acptr->name, host);
1728 return exit_client_msg(cptr, cptr, &me,
1729 "NUMERIC collision between %s and %s."
1730 " Is your server numeric correct ?", host, acptr->name);
1733 * Kill our try, if we had one.
1735 if (IsConnecting(acptr))
1737 if (!active_lh_line && exit_client(cptr, acptr, &me,
1738 "Just connected via another link") == CPTR_KILLED)
1741 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1742 * 'IsServer', because new 'IsConnecting's are refused to
1743 * the same server if we already had it.
1748 * Avoid other nick collisions...
1749 * This is a doubtfull test though, what else would it be
1750 * when it has a server.name ?
1752 else if (!IsServer(acptr) && !IsHandshake(acptr))
1753 return exit_client_msg(cptr, cptr, &me,
1754 "Nickname %s already exists!", host);
1756 * Our new server might be a juped server,
1757 * or someone trying abuse a second Uworld:
1759 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1760 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1762 if (!IsServer(sptr))
1763 return exit_client(cptr, sptr, &me, acptr->info);
1764 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
1765 me.name, parv[0], parv[1], cptr->name);
1766 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1769 * Of course we find the handshake this link was before :)
1771 else if (IsHandshake(acptr) && acptr == cptr)
1774 * Here we have a server nick collision...
1775 * We don't want to kill the link that was last /connected,
1776 * but we neither want to kill a good (old) link.
1777 * Therefor we kill the second youngest link.
1781 struct Client* c2ptr = 0;
1782 struct Client* c3ptr = acptr;
1783 struct Client* ac2ptr;
1784 struct Client* ac3ptr;
1786 /* Search youngest link: */
1787 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1788 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1792 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1793 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1796 if (timestamp > c3ptr->serv->timestamp)
1799 c2ptr = acptr; /* Make sure they differ */
1801 /* Search second youngest link: */
1802 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1803 if (ac2ptr != c3ptr &&
1804 ac2ptr->serv->timestamp >
1805 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1809 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1810 if (ac2ptr != c3ptr &&
1811 ac2ptr->serv->timestamp >
1812 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1815 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1817 /* If timestamps are equal, decide which link to break
1820 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1821 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1830 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1835 n2up = IsServer(sptr) ? sptr->name : me.name;
1840 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1845 n3up = IsServer(sptr) ? sptr->name : me.name;
1847 if (strcmp(n2, n2up) > 0)
1849 if (strcmp(n3, n3up) > 0)
1851 if (strcmp(n3, n2) > 0)
1858 /* Now squit the second youngest link: */
1860 return exit_new_server(cptr, sptr, host, timestamp,
1861 "server %s already exists and is %ld seconds younger.",
1862 host, (long)acptr->serv->timestamp - (long)timestamp);
1863 else if (c2ptr->from == cptr || IsServer(sptr))
1865 struct Client *killedptrfrom = c2ptr->from;
1869 * If the L: or H: line also gets rid of this link,
1870 * we sent just one squit.
1872 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1875 * If breaking the loop here solves the L: or H:
1876 * line problem, we don't squit that.
1878 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1883 * If we still have a L: or H: line problem,
1884 * we prefer to squit the new server, solving
1885 * loop and L:/H: line problem with only one squit.
1892 * If the new server was introduced by a server that caused a
1893 * Ghost less then 20 seconds ago, this is probably also
1894 * a Ghost... (20 seconds is more then enough because all
1895 * SERVER messages are at the beginning of a net.burst). --Run
1897 if (CurrentTime - cptr->serv->ghost < 20)
1899 killedptrfrom = acptr->from;
1900 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1903 else if (exit_client_msg(cptr, c2ptr, &me,
1904 "Loop <-- %s (new link is %ld seconds younger)", host,
1905 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1906 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1909 * Did we kill the incoming server off already ?
1911 if (killedptrfrom == cptr)
1918 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1920 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1929 * We can't believe it is a lagged server message
1930 * when it directly connects to us...
1931 * kill the older link at the ghost, rather then
1932 * at the second youngest link, assuming it isn't
1935 ghost = CurrentTime; /* Mark that it caused a ghost */
1936 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1946 return exit_new_server(cptr, sptr, host, timestamp,
1947 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1949 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1953 int killed = a_kills_b_too(LHcptr, sptr);
1954 if (active_lh_line < 3)
1956 if (exit_client_msg(cptr, LHcptr, &me,
1957 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1959 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1964 ServerStats->is_ref++;
1965 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1969 * Did we kill the incoming server off already ?
1979 * Server is informing about a new server behind
1980 * this link. Create REMOTE server structure,
1981 * add it to list and propagate word to my other
1985 acptr = make_client(cptr, STAT_SERVER);
1987 acptr->serv->prot = prot;
1988 acptr->serv->timestamp = timestamp;
1989 acptr->hopcount = hop;
1990 ircd_strncpy(acptr->name, host, HOSTLEN);
1991 ircd_strncpy(acptr->info, info, REALLEN);
1992 acptr->serv->up = sptr;
1993 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1994 /* Use cptr, because we do protocol 9 -> 10 translation
1995 for numeric nicks ! */
1996 SetServerYXX(cptr, acptr, parv[6]);
1998 Count_newremoteserver(UserStats);
1999 if (Protocol(acptr) < 10)
2000 acptr->flags |= FLAGS_TS8;
2001 add_client_to_list(acptr);
2003 if (*parv[5] == 'J')
2006 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
2007 sptr->name, acptr->name);
2011 * Old sendto_serv_but_one() call removed because we now need to send
2012 * different names to different servers (domain name matching).
2014 for (i = 0; i <= HighestFd; i++)
2016 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
2017 bcptr == cptr || IsMe(bcptr))
2019 if (0 == match(me.name, acptr->name))
2021 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
2022 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
2023 NumServCap(acptr), acptr->info);
2028 if (IsUnknown(cptr) || IsHandshake(cptr))
2031 cptr->serv->timestamp = timestamp;
2032 cptr->serv->prot = prot;
2033 cptr->serv->ghost = ghost;
2034 SetServerYXX(cptr, cptr, parv[6]);
2035 if (start_timestamp > OLDEST_TS)
2037 #ifndef RELIABLE_CLOCK
2039 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
2040 TIME_T_FMT, me.serv->timestamp, start_timestamp);
2041 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
2042 TIME_T_FMT " ; difference %ld",
2043 recv_time, timestamp, timestamp - recv_time);
2045 if (start_timestamp < me.serv->timestamp)
2047 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
2048 start_timestamp, me.serv->timestamp);
2049 me.serv->timestamp = start_timestamp;
2050 TSoffset += timestamp - recv_time;
2051 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
2053 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
2054 cptr->serv->timestamp = TStime();
2056 else if (timestamp != recv_time)
2059 * Equal start times, we have a collision. Let the connected-to server
2060 * decide. This assumes leafs issue more than half of the connection
2063 if (IsUnknown(cptr))
2064 cptr->serv->timestamp = TStime();
2065 else if (IsHandshake(cptr))
2067 sendto_ops("clock adjusted by adding %d",
2068 (int)(timestamp - recv_time));
2069 TSoffset += timestamp - recv_time;
2072 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2073 if (start_timestamp < me.serv->timestamp)
2074 me.serv->timestamp = start_timestamp;
2075 if (IsUnknown(cptr))
2076 cptr->serv->timestamp = TStime();
2080 ret = server_estab(cptr, aconf);
2084 #ifdef RELIABLE_CLOCK
2085 if (abs(cptr->serv->timestamp - recv_time) > 30)
2087 sendto_ops("Connected to a net with a timestamp-clock"
2088 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2089 " this.", timestamp - recv_time);
2090 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
2091 me.name, TStime(), me.name);