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"
102 #include "numnicks.h"
103 #include "querycmds.h"
110 #include "userload.h"
117 * mr_server - registration message handler
119 * parv[0] = sender prefix
120 * parv[1] = servername
122 * parv[3] = start timestamp
123 * parv[4] = link timestamp
124 * parv[5] = major protocol version: P09/P10
125 * parv[parc-1] = serverinfo
127 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
128 * numeric nick mask of this server.
129 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
131 int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
135 char info[REALLEN + 1];
137 struct Client* acptr;
138 struct Client* bcptr;
139 struct Client* LHcptr = 0;
140 struct ConfItem* aconf = 0;
141 struct ConfItem* cconf;
142 struct ConfItem* lhconf = 0;
143 struct Jupe* ajupe = 0;
146 int active_lh_line = 0;
148 time_t start_timestamp;
149 time_t timestamp = 0;
155 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
159 if (IsUserPort(cptr))
160 return exit_client_msg(cptr, cptr, &me,
161 "Cannot connect a server to a user port");
163 recv_time = TStime();
168 return need_more_params(sptr, "SERVER");
169 return exit_client(cptr, cptr, &me, "Need more parameters");
173 if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
174 return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
176 ircd_log(L_NOTICE, "SERVER: %s %s[%s]", parv[1], cptr->sockhost, cptr->sock_ip);
181 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
182 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
184 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
187 prot = atoi(parv[5] + 1);
188 if (prot > atoi(MAJOR_PROTOCOL))
189 prot = atoi(MAJOR_PROTOCOL);
191 * Because the previous test is only in 2.10, the following is needed
192 * till all servers are 2.10:
194 if (IsServer(cptr) && prot > Protocol(cptr))
195 prot = Protocol(cptr);
197 start_timestamp = atoi(parv[3]);
198 timestamp = atoi(parv[4]);
199 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
200 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
202 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
204 return exit_client_msg(cptr, sptr, &me,
205 "Bogus timestamps (%s %s)", parv[3], parv[4]);
207 ircd_strncpy(info, parv[parc - 1], REALLEN);
208 info[REALLEN] = '\0';
209 if (prot < atoi(MINOR_PROTOCOL)) {
210 sendto_ops("Got incompatible protocol version (%s) from %s",
211 parv[5], cptr->name);
212 return exit_new_server(cptr, sptr, host, timestamp,
213 "Incompatible protocol: %s", parv[5]);
216 * Check for "FRENCH " infection ;-) (actually this should
217 * be replaced with routine to check the hostname syntax in
218 * general). [ This check is still needed, even after the parse
219 * is fixed, because someone can send "SERVER :foo bar " ].
220 * Also, changed to check other "difficult" characters, now
221 * that parse lets all through... --msa
223 if (strlen(host) > HOSTLEN)
224 host[HOSTLEN] = '\0';
226 for (ch = host; *ch; ch++) {
227 if (*ch <= ' ' || *ch > '~')
230 if (*ch || !strchr(host, '.')) {
231 sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
232 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
238 * A local server introduces a new server behind this link.
239 * Check if this is allowed according L:, H: and Q: lines.
242 return exit_client_msg(cptr, cptr, &me,
243 "No server info specified for %s", host);
245 * See if the newly found server is behind a guaranteed
246 * leaf (L-line). If so, close the link.
248 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
249 (!lhconf->port || (hop > lhconf->port)))
252 * L: lines normally come in pairs, here we try to
253 * make sure that the oldest link is squitted, not
257 if (timestamp <= cptr->serv->timestamp)
258 LHcptr = 0; /* Kill incoming server */
260 LHcptr = cptr; /* Squit ourselfs */
262 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
263 (lhconf->port && (hop > lhconf->port)))
265 struct Client *ac3ptr;
267 /* Look for net junction causing this: */
268 LHcptr = 0; /* incoming server */
269 if (*parv[5] != 'J') {
270 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
271 if (IsJunction(ac3ptr)) {
280 if (IsUnknown(cptr) || IsHandshake(cptr))
285 * A local link that is still in undefined state wants
286 * to be a SERVER. Check if this is allowed and change
287 * status accordingly...
290 * If there is more then one server on the same machine
291 * that we try to connect to, it could be that the /CONNECT
292 * <mask> caused this connect to be put at the wrong place
293 * in the hashtable. --Run
294 * Same thing for Unknown connections that first send NICK.
296 * Better check if the two strings are (caseless) identical
297 * and not mess with hash internals.
300 if (!EmptyString(cptr->name) &&
301 (IsUnknown(cptr) || IsHandshake(cptr)) &&
302 0 != ircd_strcmp(cptr->name, host))
303 hChangeClient(cptr, host);
304 ircd_strncpy(cptr->name, host, HOSTLEN);
305 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
306 cptr->hopcount = hop;
308 /* check connection rules */
309 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
310 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
311 if (crule_eval(cconf->passwd)) {
312 ServerStats->is_ref++;
313 sendto_ops("Refused connection from %s.", cptr->name);
314 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
318 if (conf_check_server(cptr)) {
319 ++ServerStats->is_ref;
320 sendto_ops("Received unauthorized connection from %s.", cptr->name);
321 return exit_client(cptr, cptr, &me, "No C:line");
328 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
329 ++ServerStats->is_ref;
331 sendto_ops("Access denied. No conf line for server %s", cptr->name);
332 return exit_client_msg(cptr, cptr, &me,
333 "Access denied. No conf line for server %s", cptr->name);
335 sendto_ops("General C: line active: No line for server %s", cptr->name);
336 aconf = find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
338 sendto_ops("Neither C lines for server %s nor "
339 "\"general.undernet.org\"", cptr->name);
340 return exit_client_msg(cptr, cptr, &me, "No C lines for server %s", cptr->name);
344 #ifdef CRYPT_LINK_PASSWORD
345 /* passwd may be NULL. Head it off at the pass... */
349 salt[0] = aconf->passwd[0];
350 salt[1] = aconf->passwd[1];
352 encr = ircd_crypt(cptr->passwd, salt);
358 #endif /* CRYPT_LINK_PASSWORD */
360 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
361 ++ServerStats->is_ref;
362 sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
363 return exit_client_msg(cptr, cptr, &me,
364 "No Access (passwd mismatch) %s", cptr->name);
366 #endif /* not GODMODE */
367 memset(cptr->passwd, 0, sizeof(cptr->passwd));
370 for (i = 0; i <= HighestFd; i++)
371 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
380 * We want to find IsConnecting() and IsHandshake() too,
382 * The second finds collisions with numeric representation of existing
383 * servers - these shouldn't happen anymore when all upgraded to 2.10.
386 while ((acptr = FindClient(host)) ||
387 (parc > 7 && (acptr = FindNServer(parv[6]))))
390 * This link is trying feed me a server that I already have
391 * access through another path
393 * Do not allow Uworld to do this.
394 * Do not allow servers that are juped.
395 * Do not allow servers that have older link timestamps
397 * Do not allow servers that use the same numeric as an existing
398 * server, but have a different name.
400 * If my ircd.conf sucks, I can try to connect to myself:
403 return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
405 * Detect wrong numeric.
407 if (0 != ircd_strcmp(acptr->name, host)) {
408 sendto_serv_butone(cptr,
409 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
410 me.name, acptr->name, host);
411 return exit_client_msg(cptr, cptr, &me,
412 "NUMERIC collision between %s and %s."
413 " Is your server numeric correct ?", host, acptr->name);
416 * Kill our try, if we had one.
418 if (IsConnecting(acptr))
420 if (!active_lh_line && exit_client(cptr, acptr, &me,
421 "Just connected via another link") == CPTR_KILLED)
424 * We can have only ONE 'IsConnecting', 'IsHandshake' or
425 * 'IsServer', because new 'IsConnecting's are refused to
426 * the same server if we already had it.
431 * Avoid other nick collisions...
432 * This is a doubtfull test though, what else would it be
433 * when it has a server.name ?
435 else if (!IsServer(acptr) && !IsHandshake(acptr))
436 return exit_client_msg(cptr, cptr, &me,
437 "Nickname %s already exists!", host);
439 * Our new server might be a juped server,
440 * or someone trying abuse a second Uworld:
442 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
443 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
446 return exit_client(cptr, sptr, &me, acptr->info);
447 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
448 me.name, parv[0], parv[1], cptr->name);
449 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
452 * Of course we find the handshake this link was before :)
454 else if (IsHandshake(acptr) && acptr == cptr)
457 * Here we have a server nick collision...
458 * We don't want to kill the link that was last /connected,
459 * but we neither want to kill a good (old) link.
460 * Therefor we kill the second youngest link.
464 struct Client* c2ptr = 0;
465 struct Client* c3ptr = acptr;
466 struct Client* ac2ptr;
467 struct Client* ac3ptr;
469 /* Search youngest link: */
470 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
471 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
475 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
476 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
479 if (timestamp > c3ptr->serv->timestamp)
482 c2ptr = acptr; /* Make sure they differ */
484 /* Search second youngest link: */
485 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
486 if (ac2ptr != c3ptr &&
487 ac2ptr->serv->timestamp >
488 (c2ptr ? c2ptr->serv->timestamp : timestamp))
492 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
493 if (ac2ptr != c3ptr &&
494 ac2ptr->serv->timestamp >
495 (c2ptr ? c2ptr->serv->timestamp : timestamp))
498 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
500 /* If timestamps are equal, decide which link to break
503 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
504 (c3ptr ? c3ptr->serv->timestamp : timestamp))
513 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
518 n2up = IsServer(sptr) ? sptr->name : me.name;
523 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
528 n3up = IsServer(sptr) ? sptr->name : me.name;
530 if (strcmp(n2, n2up) > 0)
532 if (strcmp(n3, n3up) > 0)
534 if (strcmp(n3, n2) > 0)
541 /* Now squit the second youngest link: */
543 return exit_new_server(cptr, sptr, host, timestamp,
544 "server %s already exists and is %ld seconds younger.",
545 host, (long)acptr->serv->timestamp - (long)timestamp);
546 else if (c2ptr->from == cptr || IsServer(sptr))
548 struct Client *killedptrfrom = c2ptr->from;
552 * If the L: or H: line also gets rid of this link,
553 * we sent just one squit.
555 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
558 * If breaking the loop here solves the L: or H:
559 * line problem, we don't squit that.
561 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
566 * If we still have a L: or H: line problem,
567 * we prefer to squit the new server, solving
568 * loop and L:/H: line problem with only one squit.
575 * If the new server was introduced by a server that caused a
576 * Ghost less then 20 seconds ago, this is probably also
577 * a Ghost... (20 seconds is more then enough because all
578 * SERVER messages are at the beginning of a net.burst). --Run
580 if (CurrentTime - cptr->serv->ghost < 20)
582 killedptrfrom = acptr->from;
583 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
586 else if (exit_client_msg(cptr, c2ptr, &me,
587 "Loop <-- %s (new link is %ld seconds younger)", host,
588 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
589 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
592 * Did we kill the incoming server off already ?
594 if (killedptrfrom == cptr)
601 if (LHcptr && a_kills_b_too(LHcptr, acptr))
603 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
612 * We can't believe it is a lagged server message
613 * when it directly connects to us...
614 * kill the older link at the ghost, rather then
615 * at the second youngest link, assuming it isn't
618 ghost = CurrentTime; /* Mark that it caused a ghost */
619 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
629 return exit_new_server(cptr, sptr, host, timestamp,
630 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
631 "Leaf-only link %s <- %s(%s), check L:",
633 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
637 int killed = a_kills_b_too(LHcptr, sptr);
638 if (active_lh_line < 3)
640 if (exit_client_msg(cptr, LHcptr, &me,
641 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
642 "Leaf-only link %s <- %s(%s), check L:",
644 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
649 ServerStats->is_ref++;
650 if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
654 * Did we kill the incoming server off already ?
664 * Server is informing about a new server behind
665 * this link. Create REMOTE server structure,
666 * add it to list and propagate word to my other
670 acptr = make_client(cptr, STAT_SERVER);
672 acptr->serv->prot = prot;
673 acptr->serv->timestamp = timestamp;
674 acptr->hopcount = hop;
675 ircd_strncpy(acptr->name, host, HOSTLEN);
676 ircd_strncpy(acptr->info, info, REALLEN);
677 acptr->serv->up = sptr;
678 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
679 /* Use cptr, because we do protocol 9 -> 10 translation
680 for numeric nicks ! */
681 SetServerYXX(cptr, acptr, parv[6]);
683 Count_newremoteserver(UserStats);
684 if (Protocol(acptr) < 10)
685 acptr->flags |= FLAGS_TS8;
686 add_client_to_list(acptr);
691 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
692 sptr->name, acptr->name);
696 * Old sendto_serv_but_one() call removed because we now need to send
697 * different names to different servers (domain name matching).
699 for (i = 0; i <= HighestFd; i++)
701 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
702 bcptr == cptr || IsMe(bcptr))
704 if (0 == match(me.name, acptr->name))
706 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
707 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
708 NumServCap(acptr), acptr->info);
713 if (IsUnknown(cptr) || IsHandshake(cptr))
716 cptr->serv->timestamp = timestamp;
717 cptr->serv->prot = prot;
718 cptr->serv->ghost = ghost;
719 SetServerYXX(cptr, cptr, parv[6]);
720 if (start_timestamp > OLDEST_TS)
722 #ifndef RELIABLE_CLOCK
724 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
725 TIME_T_FMT, me.serv->timestamp, start_timestamp);
726 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
727 TIME_T_FMT " ; difference %ld",
728 recv_time, timestamp, timestamp - recv_time);
730 if (start_timestamp < me.serv->timestamp)
732 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
733 start_timestamp, me.serv->timestamp);
734 me.serv->timestamp = start_timestamp;
735 TSoffset += timestamp - recv_time;
736 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
738 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
739 cptr->serv->timestamp = TStime();
741 else if (timestamp != recv_time)
744 * Equal start times, we have a collision. Let the connected-to server
745 * decide. This assumes leafs issue more than half of the connection
749 cptr->serv->timestamp = TStime();
750 else if (IsHandshake(cptr))
752 sendto_ops("clock adjusted by adding %d",
753 (int)(timestamp - recv_time));
754 TSoffset += timestamp - recv_time;
757 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
758 if (start_timestamp < me.serv->timestamp)
759 me.serv->timestamp = start_timestamp;
761 cptr->serv->timestamp = TStime();
765 ret = server_estab(cptr, aconf);
769 #ifdef RELIABLE_CLOCK
770 if (abs(cptr->serv->timestamp - recv_time) > 30)
772 sendto_ops("Connected to a net with a timestamp-clock"
773 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
774 " this.", timestamp - recv_time);
775 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
776 me.name, TStime(), me.name);
784 * ms_server - server message handler
786 * parv[0] = sender prefix
787 * parv[1] = servername
789 * parv[3] = start timestamp
790 * parv[4] = link timestamp
791 * parv[5] = major protocol version: P09/P10
792 * parv[parc-1] = serverinfo
794 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
795 * numeric nick mask of this server.
796 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
798 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
802 char info[REALLEN + 1];
804 struct Client* acptr;
805 struct Client* bcptr;
806 struct Client* LHcptr = 0;
807 struct ConfItem* aconf = 0;
808 struct ConfItem* cconf;
809 struct ConfItem* lhconf = 0;
810 struct Jupe* ajupe = 0;
813 int active_lh_line = 0;
815 time_t start_timestamp;
816 time_t timestamp = 0;
822 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
826 if (IsUserPort(cptr))
827 return exit_client_msg(cptr, cptr, &me,
828 "Cannot connect a server to a user port");
830 recv_time = TStime();
834 return need_more_params(sptr, "SERVER");
835 return exit_client(cptr, cptr, &me, "Need more parameters");
839 if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
840 jupe_resend(cptr, ajupe);
845 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
846 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
848 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
851 prot = atoi(parv[5] + 1);
852 if (prot > atoi(MAJOR_PROTOCOL))
853 prot = atoi(MAJOR_PROTOCOL);
855 * Because the previous test is only in 2.10, the following is needed
856 * till all servers are 2.10:
858 if (IsServer(cptr) && prot > Protocol(cptr))
859 prot = Protocol(cptr);
861 start_timestamp = atoi(parv[3]);
862 timestamp = atoi(parv[4]);
863 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
864 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
865 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
867 return exit_client_msg(cptr, sptr, &me,
868 "Bogus timestamps (%s %s)", parv[3], parv[4]);
870 ircd_strncpy(info, parv[parc - 1], REALLEN);
871 info[REALLEN] = '\0';
872 if (prot < atoi(MINOR_PROTOCOL)) {
873 sendto_ops("Got incompatible protocol version (%s) from %s",
874 parv[5], cptr->name);
875 return exit_new_server(cptr, sptr, host, timestamp,
876 "Incompatible protocol: %s", parv[5]);
879 * Check for "FRENCH " infection ;-) (actually this should
880 * be replaced with routine to check the hostname syntax in
881 * general). [ This check is still needed, even after the parse
882 * is fixed, because someone can send "SERVER :foo bar " ].
883 * Also, changed to check other "difficult" characters, now
884 * that parse lets all through... --msa
886 if (strlen(host) > HOSTLEN)
887 host[HOSTLEN] = '\0';
888 for (ch = host; *ch; ch++)
889 if (*ch <= ' ' || *ch > '~')
891 if (*ch || !strchr(host, '.')) {
892 sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
893 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
899 * A local server introduces a new server behind this link.
900 * Check if this is allowed according L:, H: and Q: lines.
903 return exit_client_msg(cptr, cptr, &me,
904 "No server info specified for %s", host);
906 * See if the newly found server is behind a guaranteed
907 * leaf (L-line). If so, close the link.
909 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
910 (!lhconf->port || (hop > lhconf->port)))
913 * L: lines normally come in pairs, here we try to
914 * make sure that the oldest link is squitted, not
918 if (timestamp <= cptr->serv->timestamp)
919 LHcptr = 0; /* Kill incoming server */
921 LHcptr = cptr; /* Squit ourselfs */
923 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
924 (lhconf->port && (hop > lhconf->port)))
926 struct Client *ac3ptr;
928 /* Look for net junction causing this: */
929 LHcptr = 0; /* incoming server */
930 if (*parv[5] != 'J') {
931 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
932 if (IsJunction(ac3ptr)) {
941 if (IsUnknown(cptr) || IsHandshake(cptr))
946 * A local link that is still in undefined state wants
947 * to be a SERVER. Check if this is allowed and change
948 * status accordingly...
951 * If there is more then one server on the same machine
952 * that we try to connect to, it could be that the /CONNECT
953 * <mask> caused this connect to be put at the wrong place
954 * in the hashtable. --Run
955 * Same thing for Unknown connections that first send NICK.
957 * Better check if the two strings are (caseless) identical
958 * and not mess with hash internals.
961 if ((!(EmptyString(cptr->name)))
962 && (IsUnknown(cptr) || IsHandshake(cptr))
963 && 0 != ircd_strcmp(cptr->name, host))
964 hChangeClient(cptr, host);
965 ircd_strncpy(cptr->name, host, HOSTLEN);
966 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
967 cptr->hopcount = hop;
969 /* check connection rules */
970 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
971 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
972 if (crule_eval(cconf->passwd))
974 ServerStats->is_ref++;
975 sendto_ops("Refused connection from %s.", cptr->name);
976 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
980 if (conf_check_server(cptr)) {
981 ++ServerStats->is_ref;
982 sendto_ops("Received unauthorized connection from %s.", cptr->name);
983 return exit_client(cptr, cptr, &me, "No C conf lines");
990 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
991 ++ServerStats->is_ref;
993 sendto_ops("Access denied. No conf line for server %s", cptr->name);
994 return exit_client_msg(cptr, cptr, &me,
995 "Access denied. No conf line for server %s", cptr->name);
997 sendto_ops("General C line active: No line for server %s", cptr->name);
999 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1001 sendto_ops("Neither C lines for server %s nor "
1002 "\"general.undernet.org\"", cptr->name);
1003 return exit_client_msg(cptr, cptr, &me,
1004 "No C lines for server %s", cptr->name);
1006 #endif /* GODMODE */
1008 #ifdef CRYPT_LINK_PASSWORD
1009 /* passwd may be NULL. Head it off at the pass... */
1014 salt[0] = aconf->passwd[0];
1015 salt[1] = aconf->passwd[1];
1017 encr = ircd_crypt(cptr->passwd, salt);
1022 encr = cptr->passwd;
1023 #endif /* CRYPT_LINK_PASSWORD */
1025 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1026 ++ServerStats->is_ref;
1027 sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
1028 return exit_client_msg(cptr, cptr, &me,
1029 "No Access (passwd mismatch) %s", cptr->name);
1031 #endif /* not GODMODE */
1032 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1035 for (i = 0; i <= HighestFd; i++)
1036 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1045 * We want to find IsConnecting() and IsHandshake() too,
1047 * The second finds collisions with numeric representation of existing
1048 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1051 while ((acptr = FindClient(host)) ||
1052 (parc > 7 && (acptr = FindNServer(parv[6]))))
1055 * This link is trying feed me a server that I already have
1056 * access through another path
1058 * Do not allow Uworld to do this.
1059 * Do not allow servers that are juped.
1060 * Do not allow servers that have older link timestamps
1062 * Do not allow servers that use the same numeric as an existing
1063 * server, but have a different name.
1065 * If my ircd.conf sucks, I can try to connect to myself:
1068 return exit_client_msg(cptr, cptr, &me,
1069 "nick collision with me, check server number in M:? (%s)", host);
1071 * Detect wrong numeric.
1073 if (0 != ircd_strcmp(acptr->name, host))
1075 sendto_serv_butone(cptr,
1076 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1077 me.name, acptr->name, host);
1078 return exit_client_msg(cptr, cptr, &me,
1079 "NUMERIC collision between %s and %s."
1080 " Is your server numeric correct ?", host, acptr->name);
1083 * Kill our try, if we had one.
1085 if (IsConnecting(acptr))
1087 if (!active_lh_line && exit_client(cptr, acptr, &me,
1088 "Just connected via another link") == CPTR_KILLED)
1091 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1092 * 'IsServer', because new 'IsConnecting's are refused to
1093 * the same server if we already had it.
1098 * Avoid other nick collisions...
1099 * This is a doubtfull test though, what else would it be
1100 * when it has a server.name ?
1102 else if (!IsServer(acptr) && !IsHandshake(acptr))
1103 return exit_client_msg(cptr, cptr, &me,
1104 "Nickname %s already exists!", host);
1106 * Our new server might be a juped server,
1107 * or someone trying abuse a second Uworld:
1109 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1110 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1112 if (!IsServer(sptr))
1113 return exit_client(cptr, sptr, &me, acptr->info);
1114 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
1115 me.name, parv[0], parv[1], cptr->name);
1116 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1119 * Of course we find the handshake this link was before :)
1121 else if (IsHandshake(acptr) && acptr == cptr)
1124 * Here we have a server nick collision...
1125 * We don't want to kill the link that was last /connected,
1126 * but we neither want to kill a good (old) link.
1127 * Therefor we kill the second youngest link.
1131 struct Client* c2ptr = 0;
1132 struct Client* c3ptr = acptr;
1133 struct Client* ac2ptr;
1134 struct Client* ac3ptr;
1136 /* Search youngest link: */
1137 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1138 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1142 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1143 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1146 if (timestamp > c3ptr->serv->timestamp)
1149 c2ptr = acptr; /* Make sure they differ */
1151 /* Search second youngest link: */
1152 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1153 if (ac2ptr != c3ptr &&
1154 ac2ptr->serv->timestamp >
1155 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1159 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1160 if (ac2ptr != c3ptr &&
1161 ac2ptr->serv->timestamp >
1162 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1165 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1167 /* If timestamps are equal, decide which link to break
1170 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1171 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1180 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1185 n2up = IsServer(sptr) ? sptr->name : me.name;
1190 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1195 n3up = IsServer(sptr) ? sptr->name : me.name;
1197 if (strcmp(n2, n2up) > 0)
1199 if (strcmp(n3, n3up) > 0)
1201 if (strcmp(n3, n2) > 0)
1208 /* Now squit the second youngest link: */
1210 return exit_new_server(cptr, sptr, host, timestamp,
1211 "server %s already exists and is %ld seconds younger.",
1212 host, (long)acptr->serv->timestamp - (long)timestamp);
1213 else if (c2ptr->from == cptr || IsServer(sptr))
1215 struct Client *killedptrfrom = c2ptr->from;
1219 * If the L: or H: line also gets rid of this link,
1220 * we sent just one squit.
1222 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1225 * If breaking the loop here solves the L: or H:
1226 * line problem, we don't squit that.
1228 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1233 * If we still have a L: or H: line problem,
1234 * we prefer to squit the new server, solving
1235 * loop and L:/H: line problem with only one squit.
1242 * If the new server was introduced by a server that caused a
1243 * Ghost less then 20 seconds ago, this is probably also
1244 * a Ghost... (20 seconds is more then enough because all
1245 * SERVER messages are at the beginning of a net.burst). --Run
1247 if (CurrentTime - cptr->serv->ghost < 20)
1249 killedptrfrom = acptr->from;
1250 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1253 else if (exit_client_msg(cptr, c2ptr, &me,
1254 "Loop <-- %s (new link is %ld seconds younger)", host,
1255 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1256 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1259 * Did we kill the incoming server off already ?
1261 if (killedptrfrom == cptr)
1268 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1270 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1279 * We can't believe it is a lagged server message
1280 * when it directly connects to us...
1281 * kill the older link at the ghost, rather then
1282 * at the second youngest link, assuming it isn't
1285 ghost = CurrentTime; /* Mark that it caused a ghost */
1286 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1296 return exit_new_server(cptr, sptr, host, timestamp,
1297 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1299 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1303 int killed = a_kills_b_too(LHcptr, sptr);
1304 if (active_lh_line < 3)
1306 if (exit_client_msg(cptr, LHcptr, &me,
1307 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1309 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1314 ServerStats->is_ref++;
1315 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1319 * Did we kill the incoming server off already ?
1329 * Server is informing about a new server behind
1330 * this link. Create REMOTE server structure,
1331 * add it to list and propagate word to my other
1335 acptr = make_client(cptr, STAT_SERVER);
1337 acptr->serv->prot = prot;
1338 acptr->serv->timestamp = timestamp;
1339 acptr->hopcount = hop;
1340 ircd_strncpy(acptr->name, host, HOSTLEN);
1341 ircd_strncpy(acptr->info, info, REALLEN);
1342 acptr->serv->up = sptr;
1343 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1344 /* Use cptr, because we do protocol 9 -> 10 translation
1345 for numeric nicks ! */
1346 SetServerYXX(cptr, acptr, parv[6]);
1348 Count_newremoteserver(UserStats);
1349 if (Protocol(acptr) < 10)
1350 acptr->flags |= FLAGS_TS8;
1351 add_client_to_list(acptr);
1353 if (*parv[5] == 'J')
1356 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
1357 sptr->name, acptr->name);
1361 * Old sendto_serv_but_one() call removed because we now need to send
1362 * different names to different servers (domain name matching).
1364 for (i = 0; i <= HighestFd; i++)
1366 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1367 bcptr == cptr || IsMe(bcptr))
1369 if (0 == match(me.name, acptr->name))
1371 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
1372 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1373 NumServCap(acptr), acptr->info);
1378 if (IsUnknown(cptr) || IsHandshake(cptr))
1381 cptr->serv->timestamp = timestamp;
1382 cptr->serv->prot = prot;
1383 cptr->serv->ghost = ghost;
1384 SetServerYXX(cptr, cptr, parv[6]);
1385 if (start_timestamp > OLDEST_TS)
1387 #ifndef RELIABLE_CLOCK
1389 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
1390 TIME_T_FMT, me.serv->timestamp, start_timestamp);
1391 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
1392 TIME_T_FMT " ; difference %ld",
1393 recv_time, timestamp, timestamp - recv_time);
1395 if (start_timestamp < me.serv->timestamp)
1397 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
1398 start_timestamp, me.serv->timestamp);
1399 me.serv->timestamp = start_timestamp;
1400 TSoffset += timestamp - recv_time;
1401 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
1403 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1404 cptr->serv->timestamp = TStime();
1406 else if (timestamp != recv_time)
1409 * Equal start times, we have a collision. Let the connected-to server
1410 * decide. This assumes leafs issue more than half of the connection
1413 if (IsUnknown(cptr))
1414 cptr->serv->timestamp = TStime();
1415 else if (IsHandshake(cptr))
1417 sendto_ops("clock adjusted by adding %d",
1418 (int)(timestamp - recv_time));
1419 TSoffset += timestamp - recv_time;
1422 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
1423 if (start_timestamp < me.serv->timestamp)
1424 me.serv->timestamp = start_timestamp;
1425 if (IsUnknown(cptr))
1426 cptr->serv->timestamp = TStime();
1430 ret = server_estab(cptr, aconf);
1434 #ifdef RELIABLE_CLOCK
1435 if (abs(cptr->serv->timestamp - recv_time) > 30)
1437 sendto_ops("Connected to a net with a timestamp-clock"
1438 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
1439 " this.", timestamp - recv_time);
1440 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
1441 me.name, TStime(), me.name);
1453 * parv[0] = sender prefix
1454 * parv[1] = servername
1455 * parv[2] = hopcount
1456 * parv[3] = start timestamp
1457 * parv[4] = link timestamp
1458 * parv[5] = major protocol version: P09/P10
1459 * parv[parc-1] = serverinfo
1461 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1462 * numeric nick mask of this server.
1463 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1465 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1469 char info[REALLEN + 1];
1471 struct Client* acptr;
1472 struct Client* bcptr;
1473 struct Client* LHcptr = 0;
1474 struct ConfItem* aconf = 0;
1475 struct ConfItem* cconf;
1476 struct ConfItem* lhconf = 0;
1477 struct Jupe* ajupe = 0;
1480 int active_lh_line = 0;
1481 unsigned short prot;
1482 time_t start_timestamp;
1483 time_t timestamp = 0;
1489 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
1493 if (IsUserPort(cptr))
1494 return exit_client_msg(cptr, cptr, &me,
1495 "You cannot connect a server to a user port; connect to %s port %u",
1496 me.name, server_port);
1498 recv_time = TStime();
1502 return need_more_params(sptr, "SERVER");
1503 return exit_client(cptr, cptr, &me, "Need more parameters");
1509 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1510 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1512 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1515 prot = atoi(parv[5] + 1);
1516 if (prot > atoi(MAJOR_PROTOCOL))
1517 prot = atoi(MAJOR_PROTOCOL);
1519 * Because the previous test is only in 2.10, the following is needed
1520 * till all servers are 2.10:
1522 if (IsServer(cptr) && prot > Protocol(cptr))
1523 prot = Protocol(cptr);
1524 hop = atoi(parv[2]);
1525 start_timestamp = atoi(parv[3]);
1526 timestamp = atoi(parv[4]);
1527 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1528 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1529 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1531 return exit_client_msg(cptr, sptr, &me,
1532 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1534 ircd_strncpy(info, parv[parc - 1], REALLEN);
1535 info[REALLEN] = '\0';
1536 if (prot < atoi(MINOR_PROTOCOL)) {
1537 sendto_ops("Got incompatible protocol version (%s) from %s",
1538 parv[5], cptr->name);
1539 return exit_new_server(cptr, sptr, host, timestamp,
1540 "Incompatible protocol: %s", parv[5]);
1543 * Check for "FRENCH " infection ;-) (actually this should
1544 * be replaced with routine to check the hostname syntax in
1545 * general). [ This check is still needed, even after the parse
1546 * is fixed, because someone can send "SERVER :foo bar " ].
1547 * Also, changed to check other "difficult" characters, now
1548 * that parse lets all through... --msa
1550 if (strlen(host) > HOSTLEN)
1551 host[HOSTLEN] = '\0';
1552 for (ch = host; *ch; ch++)
1553 if (*ch <= ' ' || *ch > '~')
1555 if (*ch || !strchr(host, '.'))
1557 sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
1558 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1564 * A local server introduces a new server behind this link.
1565 * Check if this is allowed according L:, H: and Q: lines.
1567 if (info[0] == '\0')
1568 return exit_client_msg(cptr, cptr, &me,
1569 "No server info specified for %s", host);
1571 * See if the newly found server is behind a guaranteed
1572 * leaf (L-line). If so, close the link.
1574 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1575 (!lhconf->port || (hop > lhconf->port)))
1578 * L: lines normally come in pairs, here we try to
1579 * make sure that the oldest link is squitted, not
1583 if (timestamp <= cptr->serv->timestamp)
1584 LHcptr = 0; /* Kill incoming server */
1586 LHcptr = cptr; /* Squit ourselfs */
1588 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1589 (lhconf->port && (hop > lhconf->port)))
1591 struct Client *ac3ptr;
1593 /* Look for net junction causing this: */
1594 LHcptr = 0; /* incoming server */
1595 if (*parv[5] != 'J') {
1596 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1597 if (IsJunction(ac3ptr)) {
1606 if (IsUnknown(cptr) || IsHandshake(cptr))
1611 * A local link that is still in undefined state wants
1612 * to be a SERVER. Check if this is allowed and change
1613 * status accordingly...
1616 * If there is more then one server on the same machine
1617 * that we try to connect to, it could be that the /CONNECT
1618 * <mask> caused this connect to be put at the wrong place
1619 * in the hashtable. --Run
1620 * Same thing for Unknown connections that first send NICK.
1622 * Better check if the two strings are (caseless) identical
1623 * and not mess with hash internals.
1626 if ((!(EmptyString(cptr->name)))
1627 && (IsUnknown(cptr) || IsHandshake(cptr))
1628 && 0 != ircd_strcmp(cptr->name, host))
1629 hChangeClient(cptr, host);
1630 ircd_strncpy(cptr->name, host, HOSTLEN);
1631 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1632 cptr->hopcount = hop;
1634 /* check connection rules */
1635 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
1636 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
1637 if (crule_eval(cconf->passwd))
1639 ServerStats->is_ref++;
1640 sendto_ops("Refused connection from %s.", cptr->name);
1641 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1645 if (conf_check_server(cptr)) {
1646 ++ServerStats->is_ref;
1647 sendto_ops("Received unauthorized connection from %s.", cptr->name);
1648 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1655 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1656 ++ServerStats->is_ref;
1658 sendto_ops("Access denied. No conf line for server %s", cptr->name);
1659 return exit_client_msg(cptr, cptr, &me,
1660 "Access denied. No conf line for server %s", cptr->name);
1662 sendto_ops("General C/N: line active: No line for server %s", cptr->name);
1664 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1666 sendto_ops("Neither C/N lines for server %s nor "
1667 "\"general.undernet.org\"", cptr->name);
1668 return exit_client_msg(cptr, cptr, &me,
1669 "No C/N lines for server %s", cptr->name);
1671 #endif /* GODMODE */
1673 #ifdef CRYPT_LINK_PASSWORD
1674 /* passwd may be NULL. Head it off at the pass... */
1679 salt[0] = aconf->passwd[0];
1680 salt[1] = aconf->passwd[1];
1682 encr = ircd_crypt(cptr->passwd, salt);
1687 encr = cptr->passwd;
1688 #endif /* CRYPT_LINK_PASSWORD */
1690 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1691 ++ServerStats->is_ref;
1692 sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
1693 return exit_client_msg(cptr, cptr, &me,
1694 "No Access (passwd mismatch) %s", cptr->name);
1696 #endif /* not GODMODE */
1697 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1700 for (i = 0; i <= HighestFd; i++)
1701 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1710 * We want to find IsConnecting() and IsHandshake() too,
1712 * The second finds collisions with numeric representation of existing
1713 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1716 while ((acptr = FindClient(host)) ||
1717 (parc > 7 && (acptr = FindNServer(parv[6]))))
1720 * This link is trying feed me a server that I already have
1721 * access through another path
1723 * Do not allow Uworld to do this.
1724 * Do not allow servers that are juped.
1725 * Do not allow servers that have older link timestamps
1727 * Do not allow servers that use the same numeric as an existing
1728 * server, but have a different name.
1730 * If my ircd.conf sucks, I can try to connect to myself:
1733 return exit_client_msg(cptr, cptr, &me,
1734 "nick collision with me, check server number in M:? (%s)", host);
1736 * Detect wrong numeric.
1738 if (0 != ircd_strcmp(acptr->name, host))
1740 sendto_serv_butone(cptr,
1741 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1742 me.name, acptr->name, host);
1743 return exit_client_msg(cptr, cptr, &me,
1744 "NUMERIC collision between %s and %s."
1745 " Is your server numeric correct ?", host, acptr->name);
1748 * Kill our try, if we had one.
1750 if (IsConnecting(acptr))
1752 if (!active_lh_line && exit_client(cptr, acptr, &me,
1753 "Just connected via another link") == CPTR_KILLED)
1756 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1757 * 'IsServer', because new 'IsConnecting's are refused to
1758 * the same server if we already had it.
1763 * Avoid other nick collisions...
1764 * This is a doubtfull test though, what else would it be
1765 * when it has a server.name ?
1767 else if (!IsServer(acptr) && !IsHandshake(acptr))
1768 return exit_client_msg(cptr, cptr, &me,
1769 "Nickname %s already exists!", host);
1771 * Our new server might be a juped server,
1772 * or someone trying abuse a second Uworld:
1774 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1775 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1777 if (!IsServer(sptr))
1778 return exit_client(cptr, sptr, &me, acptr->info);
1779 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
1780 me.name, parv[0], parv[1], cptr->name);
1781 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1784 * Of course we find the handshake this link was before :)
1786 else if (IsHandshake(acptr) && acptr == cptr)
1789 * Here we have a server nick collision...
1790 * We don't want to kill the link that was last /connected,
1791 * but we neither want to kill a good (old) link.
1792 * Therefor we kill the second youngest link.
1796 struct Client* c2ptr = 0;
1797 struct Client* c3ptr = acptr;
1798 struct Client* ac2ptr;
1799 struct Client* ac3ptr;
1801 /* Search youngest link: */
1802 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1803 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1807 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1808 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1811 if (timestamp > c3ptr->serv->timestamp)
1814 c2ptr = acptr; /* Make sure they differ */
1816 /* Search second youngest link: */
1817 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1818 if (ac2ptr != c3ptr &&
1819 ac2ptr->serv->timestamp >
1820 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1824 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1825 if (ac2ptr != c3ptr &&
1826 ac2ptr->serv->timestamp >
1827 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1830 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1832 /* If timestamps are equal, decide which link to break
1835 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1836 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1845 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1850 n2up = IsServer(sptr) ? sptr->name : me.name;
1855 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1860 n3up = IsServer(sptr) ? sptr->name : me.name;
1862 if (strcmp(n2, n2up) > 0)
1864 if (strcmp(n3, n3up) > 0)
1866 if (strcmp(n3, n2) > 0)
1873 /* Now squit the second youngest link: */
1875 return exit_new_server(cptr, sptr, host, timestamp,
1876 "server %s already exists and is %ld seconds younger.",
1877 host, (long)acptr->serv->timestamp - (long)timestamp);
1878 else if (c2ptr->from == cptr || IsServer(sptr))
1880 struct Client *killedptrfrom = c2ptr->from;
1884 * If the L: or H: line also gets rid of this link,
1885 * we sent just one squit.
1887 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1890 * If breaking the loop here solves the L: or H:
1891 * line problem, we don't squit that.
1893 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1898 * If we still have a L: or H: line problem,
1899 * we prefer to squit the new server, solving
1900 * loop and L:/H: line problem with only one squit.
1907 * If the new server was introduced by a server that caused a
1908 * Ghost less then 20 seconds ago, this is probably also
1909 * a Ghost... (20 seconds is more then enough because all
1910 * SERVER messages are at the beginning of a net.burst). --Run
1912 if (CurrentTime - cptr->serv->ghost < 20)
1914 killedptrfrom = acptr->from;
1915 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1918 else if (exit_client_msg(cptr, c2ptr, &me,
1919 "Loop <-- %s (new link is %ld seconds younger)", host,
1920 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1921 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1924 * Did we kill the incoming server off already ?
1926 if (killedptrfrom == cptr)
1933 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1935 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1944 * We can't believe it is a lagged server message
1945 * when it directly connects to us...
1946 * kill the older link at the ghost, rather then
1947 * at the second youngest link, assuming it isn't
1950 ghost = CurrentTime; /* Mark that it caused a ghost */
1951 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1961 return exit_new_server(cptr, sptr, host, timestamp,
1962 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1964 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1968 int killed = a_kills_b_too(LHcptr, sptr);
1969 if (active_lh_line < 3)
1971 if (exit_client_msg(cptr, LHcptr, &me,
1972 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1974 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1979 ServerStats->is_ref++;
1980 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1984 * Did we kill the incoming server off already ?
1994 * Server is informing about a new server behind
1995 * this link. Create REMOTE server structure,
1996 * add it to list and propagate word to my other
2000 acptr = make_client(cptr, STAT_SERVER);
2002 acptr->serv->prot = prot;
2003 acptr->serv->timestamp = timestamp;
2004 acptr->hopcount = hop;
2005 ircd_strncpy(acptr->name, host, HOSTLEN);
2006 ircd_strncpy(acptr->info, info, REALLEN);
2007 acptr->serv->up = sptr;
2008 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
2009 /* Use cptr, because we do protocol 9 -> 10 translation
2010 for numeric nicks ! */
2011 SetServerYXX(cptr, acptr, parv[6]);
2013 Count_newremoteserver(UserStats);
2014 if (Protocol(acptr) < 10)
2015 acptr->flags |= FLAGS_TS8;
2016 add_client_to_list(acptr);
2018 if (*parv[5] == 'J')
2021 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
2022 sptr->name, acptr->name);
2026 * Old sendto_serv_but_one() call removed because we now need to send
2027 * different names to different servers (domain name matching).
2029 for (i = 0; i <= HighestFd; i++)
2031 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
2032 bcptr == cptr || IsMe(bcptr))
2034 if (0 == match(me.name, acptr->name))
2036 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
2037 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
2038 NumServCap(acptr), acptr->info);
2043 if (IsUnknown(cptr) || IsHandshake(cptr))
2046 cptr->serv->timestamp = timestamp;
2047 cptr->serv->prot = prot;
2048 cptr->serv->ghost = ghost;
2049 SetServerYXX(cptr, cptr, parv[6]);
2050 if (start_timestamp > OLDEST_TS)
2052 #ifndef RELIABLE_CLOCK
2054 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
2055 TIME_T_FMT, me.serv->timestamp, start_timestamp);
2056 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
2057 TIME_T_FMT " ; difference %ld",
2058 recv_time, timestamp, timestamp - recv_time);
2060 if (start_timestamp < me.serv->timestamp)
2062 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
2063 start_timestamp, me.serv->timestamp);
2064 me.serv->timestamp = start_timestamp;
2065 TSoffset += timestamp - recv_time;
2066 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
2068 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
2069 cptr->serv->timestamp = TStime();
2071 else if (timestamp != recv_time)
2074 * Equal start times, we have a collision. Let the connected-to server
2075 * decide. This assumes leafs issue more than half of the connection
2078 if (IsUnknown(cptr))
2079 cptr->serv->timestamp = TStime();
2080 else if (IsHandshake(cptr))
2082 sendto_ops("clock adjusted by adding %d",
2083 (int)(timestamp - recv_time));
2084 TSoffset += timestamp - recv_time;
2087 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2088 if (start_timestamp < me.serv->timestamp)
2089 me.serv->timestamp = start_timestamp;
2090 if (IsUnknown(cptr))
2091 cptr->serv->timestamp = TStime();
2095 ret = server_estab(cptr, aconf);
2099 #ifdef RELIABLE_CLOCK
2100 if (abs(cptr->serv->timestamp - recv_time) > 30)
2102 sendto_ops("Connected to a net with a timestamp-clock"
2103 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2104 " this.", timestamp - recv_time);
2105 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
2106 me.name, TStime(), me.name);