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)", 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)" : "Leaf-only link %s <- %s(%s)",
632 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
636 int killed = a_kills_b_too(LHcptr, sptr);
637 if (active_lh_line < 3)
639 if (exit_client_msg(cptr, LHcptr, &me,
640 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
642 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
647 ServerStats->is_ref++;
648 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
652 * Did we kill the incoming server off already ?
662 * Server is informing about a new server behind
663 * this link. Create REMOTE server structure,
664 * add it to list and propagate word to my other
668 acptr = make_client(cptr, STAT_SERVER);
670 acptr->serv->prot = prot;
671 acptr->serv->timestamp = timestamp;
672 acptr->hopcount = hop;
673 ircd_strncpy(acptr->name, host, HOSTLEN);
674 ircd_strncpy(acptr->info, info, REALLEN);
675 acptr->serv->up = sptr;
676 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
677 /* Use cptr, because we do protocol 9 -> 10 translation
678 for numeric nicks ! */
679 SetServerYXX(cptr, acptr, parv[6]);
681 Count_newremoteserver(UserStats);
682 if (Protocol(acptr) < 10)
683 acptr->flags |= FLAGS_TS8;
684 add_client_to_list(acptr);
689 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
690 sptr->name, acptr->name);
694 * Old sendto_serv_but_one() call removed because we now need to send
695 * different names to different servers (domain name matching).
697 for (i = 0; i <= HighestFd; i++)
699 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
700 bcptr == cptr || IsMe(bcptr))
702 if (0 == match(me.name, acptr->name))
704 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
705 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
706 NumServCap(acptr), acptr->info);
711 if (IsUnknown(cptr) || IsHandshake(cptr))
714 cptr->serv->timestamp = timestamp;
715 cptr->serv->prot = prot;
716 cptr->serv->ghost = ghost;
717 SetServerYXX(cptr, cptr, parv[6]);
718 if (start_timestamp > OLDEST_TS)
720 #ifndef RELIABLE_CLOCK
722 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
723 TIME_T_FMT, me.serv->timestamp, start_timestamp);
724 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
725 TIME_T_FMT " ; difference %ld",
726 recv_time, timestamp, timestamp - recv_time);
728 if (start_timestamp < me.serv->timestamp)
730 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
731 start_timestamp, me.serv->timestamp);
732 me.serv->timestamp = start_timestamp;
733 TSoffset += timestamp - recv_time;
734 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
736 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
737 cptr->serv->timestamp = TStime();
739 else if (timestamp != recv_time)
742 * Equal start times, we have a collision. Let the connected-to server
743 * decide. This assumes leafs issue more than half of the connection
747 cptr->serv->timestamp = TStime();
748 else if (IsHandshake(cptr))
750 sendto_ops("clock adjusted by adding %d",
751 (int)(timestamp - recv_time));
752 TSoffset += timestamp - recv_time;
755 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
756 if (start_timestamp < me.serv->timestamp)
757 me.serv->timestamp = start_timestamp;
759 cptr->serv->timestamp = TStime();
763 ret = server_estab(cptr, aconf);
767 #ifdef RELIABLE_CLOCK
768 if (abs(cptr->serv->timestamp - recv_time) > 30)
770 sendto_ops("Connected to a net with a timestamp-clock"
771 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
772 " this.", timestamp - recv_time);
773 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
774 me.name, TStime(), me.name);
782 * ms_server - server message handler
784 * parv[0] = sender prefix
785 * parv[1] = servername
787 * parv[3] = start timestamp
788 * parv[4] = link timestamp
789 * parv[5] = major protocol version: P09/P10
790 * parv[parc-1] = serverinfo
792 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
793 * numeric nick mask of this server.
794 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
796 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
800 char info[REALLEN + 1];
802 struct Client* acptr;
803 struct Client* bcptr;
804 struct Client* LHcptr = 0;
805 struct ConfItem* aconf = 0;
806 struct ConfItem* cconf;
807 struct ConfItem* lhconf = 0;
808 struct Jupe* ajupe = 0;
811 int active_lh_line = 0;
813 time_t start_timestamp;
814 time_t timestamp = 0;
820 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
824 if (IsUserPort(cptr))
825 return exit_client_msg(cptr, cptr, &me,
826 "Cannot connect a server to a user port");
828 recv_time = TStime();
832 return need_more_params(sptr, "SERVER");
833 return exit_client(cptr, cptr, &me, "Need more parameters");
837 if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
838 jupe_resend(cptr, ajupe);
843 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
844 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
846 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
849 prot = atoi(parv[5] + 1);
850 if (prot > atoi(MAJOR_PROTOCOL))
851 prot = atoi(MAJOR_PROTOCOL);
853 * Because the previous test is only in 2.10, the following is needed
854 * till all servers are 2.10:
856 if (IsServer(cptr) && prot > Protocol(cptr))
857 prot = Protocol(cptr);
859 start_timestamp = atoi(parv[3]);
860 timestamp = atoi(parv[4]);
861 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
862 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
863 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
865 return exit_client_msg(cptr, sptr, &me,
866 "Bogus timestamps (%s %s)", parv[3], parv[4]);
868 ircd_strncpy(info, parv[parc - 1], REALLEN);
869 info[REALLEN] = '\0';
870 if (prot < atoi(MINOR_PROTOCOL)) {
871 sendto_ops("Got incompatible protocol version (%s) from %s",
872 parv[5], cptr->name);
873 return exit_new_server(cptr, sptr, host, timestamp,
874 "Incompatible protocol: %s", parv[5]);
877 * Check for "FRENCH " infection ;-) (actually this should
878 * be replaced with routine to check the hostname syntax in
879 * general). [ This check is still needed, even after the parse
880 * is fixed, because someone can send "SERVER :foo bar " ].
881 * Also, changed to check other "difficult" characters, now
882 * that parse lets all through... --msa
884 if (strlen(host) > HOSTLEN)
885 host[HOSTLEN] = '\0';
886 for (ch = host; *ch; ch++)
887 if (*ch <= ' ' || *ch > '~')
889 if (*ch || !strchr(host, '.')) {
890 sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
891 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
897 * A local server introduces a new server behind this link.
898 * Check if this is allowed according L:, H: and Q: lines.
901 return exit_client_msg(cptr, cptr, &me,
902 "No server info specified for %s", host);
904 * See if the newly found server is behind a guaranteed
905 * leaf (L-line). If so, close the link.
907 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
908 (!lhconf->port || (hop > lhconf->port)))
911 * L: lines normally come in pairs, here we try to
912 * make sure that the oldest link is squitted, not
916 if (timestamp <= cptr->serv->timestamp)
917 LHcptr = 0; /* Kill incoming server */
919 LHcptr = cptr; /* Squit ourselfs */
921 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
922 (lhconf->port && (hop > lhconf->port)))
924 struct Client *ac3ptr;
926 /* Look for net junction causing this: */
927 LHcptr = 0; /* incoming server */
928 if (*parv[5] != 'J') {
929 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
930 if (IsJunction(ac3ptr)) {
939 if (IsUnknown(cptr) || IsHandshake(cptr))
944 * A local link that is still in undefined state wants
945 * to be a SERVER. Check if this is allowed and change
946 * status accordingly...
949 * If there is more then one server on the same machine
950 * that we try to connect to, it could be that the /CONNECT
951 * <mask> caused this connect to be put at the wrong place
952 * in the hashtable. --Run
953 * Same thing for Unknown connections that first send NICK.
955 * Better check if the two strings are (caseless) identical
956 * and not mess with hash internals.
959 if ((!(EmptyString(cptr->name)))
960 && (IsUnknown(cptr) || IsHandshake(cptr))
961 && 0 != ircd_strcmp(cptr->name, host))
962 hChangeClient(cptr, host);
963 ircd_strncpy(cptr->name, host, HOSTLEN);
964 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
965 cptr->hopcount = hop;
967 /* check connection rules */
968 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
969 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
970 if (crule_eval(cconf->passwd))
972 ServerStats->is_ref++;
973 sendto_ops("Refused connection from %s.", cptr->name);
974 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
978 if (conf_check_server(cptr)) {
979 ++ServerStats->is_ref;
980 sendto_ops("Received unauthorized connection from %s.", cptr->name);
981 return exit_client(cptr, cptr, &me, "No C conf lines");
988 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
989 ++ServerStats->is_ref;
991 sendto_ops("Access denied. No conf line for server %s", cptr->name);
992 return exit_client_msg(cptr, cptr, &me,
993 "Access denied. No conf line for server %s", cptr->name);
995 sendto_ops("General C line active: No line for server %s", cptr->name);
997 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
999 sendto_ops("Neither C lines for server %s nor "
1000 "\"general.undernet.org\"", cptr->name);
1001 return exit_client_msg(cptr, cptr, &me,
1002 "No C lines for server %s", cptr->name);
1004 #endif /* GODMODE */
1006 #ifdef CRYPT_LINK_PASSWORD
1007 /* passwd may be NULL. Head it off at the pass... */
1012 salt[0] = aconf->passwd[0];
1013 salt[1] = aconf->passwd[1];
1015 encr = ircd_crypt(cptr->passwd, salt);
1020 encr = cptr->passwd;
1021 #endif /* CRYPT_LINK_PASSWORD */
1023 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1024 ++ServerStats->is_ref;
1025 sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
1026 return exit_client_msg(cptr, cptr, &me,
1027 "No Access (passwd mismatch) %s", cptr->name);
1029 #endif /* not GODMODE */
1030 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1033 for (i = 0; i <= HighestFd; i++)
1034 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1043 * We want to find IsConnecting() and IsHandshake() too,
1045 * The second finds collisions with numeric representation of existing
1046 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1049 while ((acptr = FindClient(host)) ||
1050 (parc > 7 && (acptr = FindNServer(parv[6]))))
1053 * This link is trying feed me a server that I already have
1054 * access through another path
1056 * Do not allow Uworld to do this.
1057 * Do not allow servers that are juped.
1058 * Do not allow servers that have older link timestamps
1060 * Do not allow servers that use the same numeric as an existing
1061 * server, but have a different name.
1063 * If my ircd.conf sucks, I can try to connect to myself:
1066 return exit_client_msg(cptr, cptr, &me,
1067 "nick collision with me (%s)", host);
1069 * Detect wrong numeric.
1071 if (0 != ircd_strcmp(acptr->name, host))
1073 sendto_serv_butone(cptr,
1074 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1075 me.name, acptr->name, host);
1076 return exit_client_msg(cptr, cptr, &me,
1077 "NUMERIC collision between %s and %s."
1078 " Is your server numeric correct ?", host, acptr->name);
1081 * Kill our try, if we had one.
1083 if (IsConnecting(acptr))
1085 if (!active_lh_line && exit_client(cptr, acptr, &me,
1086 "Just connected via another link") == CPTR_KILLED)
1089 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1090 * 'IsServer', because new 'IsConnecting's are refused to
1091 * the same server if we already had it.
1096 * Avoid other nick collisions...
1097 * This is a doubtfull test though, what else would it be
1098 * when it has a server.name ?
1100 else if (!IsServer(acptr) && !IsHandshake(acptr))
1101 return exit_client_msg(cptr, cptr, &me,
1102 "Nickname %s already exists!", host);
1104 * Our new server might be a juped server,
1105 * or someone trying abuse a second Uworld:
1107 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1108 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1110 if (!IsServer(sptr))
1111 return exit_client(cptr, sptr, &me, acptr->info);
1112 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
1113 me.name, parv[0], parv[1], cptr->name);
1114 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1117 * Of course we find the handshake this link was before :)
1119 else if (IsHandshake(acptr) && acptr == cptr)
1122 * Here we have a server nick collision...
1123 * We don't want to kill the link that was last /connected,
1124 * but we neither want to kill a good (old) link.
1125 * Therefor we kill the second youngest link.
1129 struct Client* c2ptr = 0;
1130 struct Client* c3ptr = acptr;
1131 struct Client* ac2ptr;
1132 struct Client* ac3ptr;
1134 /* Search youngest link: */
1135 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1136 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1140 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1141 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1144 if (timestamp > c3ptr->serv->timestamp)
1147 c2ptr = acptr; /* Make sure they differ */
1149 /* Search second youngest link: */
1150 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1151 if (ac2ptr != c3ptr &&
1152 ac2ptr->serv->timestamp >
1153 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1157 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1158 if (ac2ptr != c3ptr &&
1159 ac2ptr->serv->timestamp >
1160 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1163 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1165 /* If timestamps are equal, decide which link to break
1168 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1169 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1178 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1183 n2up = IsServer(sptr) ? sptr->name : me.name;
1188 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1193 n3up = IsServer(sptr) ? sptr->name : me.name;
1195 if (strcmp(n2, n2up) > 0)
1197 if (strcmp(n3, n3up) > 0)
1199 if (strcmp(n3, n2) > 0)
1206 /* Now squit the second youngest link: */
1208 return exit_new_server(cptr, sptr, host, timestamp,
1209 "server %s already exists and is %ld seconds younger.",
1210 host, (long)acptr->serv->timestamp - (long)timestamp);
1211 else if (c2ptr->from == cptr || IsServer(sptr))
1213 struct Client *killedptrfrom = c2ptr->from;
1217 * If the L: or H: line also gets rid of this link,
1218 * we sent just one squit.
1220 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1223 * If breaking the loop here solves the L: or H:
1224 * line problem, we don't squit that.
1226 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1231 * If we still have a L: or H: line problem,
1232 * we prefer to squit the new server, solving
1233 * loop and L:/H: line problem with only one squit.
1240 * If the new server was introduced by a server that caused a
1241 * Ghost less then 20 seconds ago, this is probably also
1242 * a Ghost... (20 seconds is more then enough because all
1243 * SERVER messages are at the beginning of a net.burst). --Run
1245 if (CurrentTime - cptr->serv->ghost < 20)
1247 killedptrfrom = acptr->from;
1248 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1251 else if (exit_client_msg(cptr, c2ptr, &me,
1252 "Loop <-- %s (new link is %ld seconds younger)", host,
1253 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1254 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1257 * Did we kill the incoming server off already ?
1259 if (killedptrfrom == cptr)
1266 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1268 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1277 * We can't believe it is a lagged server message
1278 * when it directly connects to us...
1279 * kill the older link at the ghost, rather then
1280 * at the second youngest link, assuming it isn't
1283 ghost = CurrentTime; /* Mark that it caused a ghost */
1284 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1294 return exit_new_server(cptr, sptr, host, timestamp,
1295 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1297 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1301 int killed = a_kills_b_too(LHcptr, sptr);
1302 if (active_lh_line < 3)
1304 if (exit_client_msg(cptr, LHcptr, &me,
1305 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1307 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1312 ServerStats->is_ref++;
1313 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1317 * Did we kill the incoming server off already ?
1327 * Server is informing about a new server behind
1328 * this link. Create REMOTE server structure,
1329 * add it to list and propagate word to my other
1333 acptr = make_client(cptr, STAT_SERVER);
1335 acptr->serv->prot = prot;
1336 acptr->serv->timestamp = timestamp;
1337 acptr->hopcount = hop;
1338 ircd_strncpy(acptr->name, host, HOSTLEN);
1339 ircd_strncpy(acptr->info, info, REALLEN);
1340 acptr->serv->up = sptr;
1341 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1342 /* Use cptr, because we do protocol 9 -> 10 translation
1343 for numeric nicks ! */
1344 SetServerYXX(cptr, acptr, parv[6]);
1346 Count_newremoteserver(UserStats);
1347 if (Protocol(acptr) < 10)
1348 acptr->flags |= FLAGS_TS8;
1349 add_client_to_list(acptr);
1351 if (*parv[5] == 'J')
1354 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
1355 sptr->name, acptr->name);
1359 * Old sendto_serv_but_one() call removed because we now need to send
1360 * different names to different servers (domain name matching).
1362 for (i = 0; i <= HighestFd; i++)
1364 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1365 bcptr == cptr || IsMe(bcptr))
1367 if (0 == match(me.name, acptr->name))
1369 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
1370 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1371 NumServCap(acptr), acptr->info);
1376 if (IsUnknown(cptr) || IsHandshake(cptr))
1379 cptr->serv->timestamp = timestamp;
1380 cptr->serv->prot = prot;
1381 cptr->serv->ghost = ghost;
1382 SetServerYXX(cptr, cptr, parv[6]);
1383 if (start_timestamp > OLDEST_TS)
1385 #ifndef RELIABLE_CLOCK
1387 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
1388 TIME_T_FMT, me.serv->timestamp, start_timestamp);
1389 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
1390 TIME_T_FMT " ; difference %ld",
1391 recv_time, timestamp, timestamp - recv_time);
1393 if (start_timestamp < me.serv->timestamp)
1395 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
1396 start_timestamp, me.serv->timestamp);
1397 me.serv->timestamp = start_timestamp;
1398 TSoffset += timestamp - recv_time;
1399 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
1401 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1402 cptr->serv->timestamp = TStime();
1404 else if (timestamp != recv_time)
1407 * Equal start times, we have a collision. Let the connected-to server
1408 * decide. This assumes leafs issue more than half of the connection
1411 if (IsUnknown(cptr))
1412 cptr->serv->timestamp = TStime();
1413 else if (IsHandshake(cptr))
1415 sendto_ops("clock adjusted by adding %d",
1416 (int)(timestamp - recv_time));
1417 TSoffset += timestamp - recv_time;
1420 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
1421 if (start_timestamp < me.serv->timestamp)
1422 me.serv->timestamp = start_timestamp;
1423 if (IsUnknown(cptr))
1424 cptr->serv->timestamp = TStime();
1428 ret = server_estab(cptr, aconf);
1432 #ifdef RELIABLE_CLOCK
1433 if (abs(cptr->serv->timestamp - recv_time) > 30)
1435 sendto_ops("Connected to a net with a timestamp-clock"
1436 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
1437 " this.", timestamp - recv_time);
1438 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
1439 me.name, TStime(), me.name);
1451 * parv[0] = sender prefix
1452 * parv[1] = servername
1453 * parv[2] = hopcount
1454 * parv[3] = start timestamp
1455 * parv[4] = link timestamp
1456 * parv[5] = major protocol version: P09/P10
1457 * parv[parc-1] = serverinfo
1459 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1460 * numeric nick mask of this server.
1461 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1463 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1467 char info[REALLEN + 1];
1469 struct Client* acptr;
1470 struct Client* bcptr;
1471 struct Client* LHcptr = 0;
1472 struct ConfItem* aconf = 0;
1473 struct ConfItem* cconf;
1474 struct ConfItem* lhconf = 0;
1475 struct Jupe* ajupe = 0;
1478 int active_lh_line = 0;
1479 unsigned short prot;
1480 time_t start_timestamp;
1481 time_t timestamp = 0;
1487 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
1491 if (IsUserPort(cptr))
1492 return exit_client_msg(cptr, cptr, &me,
1493 "You cannot connect a server to a user port; connect to %s port %u",
1494 me.name, server_port);
1496 recv_time = TStime();
1500 return need_more_params(sptr, "SERVER");
1501 return exit_client(cptr, cptr, &me, "Need more parameters");
1507 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1508 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1510 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1513 prot = atoi(parv[5] + 1);
1514 if (prot > atoi(MAJOR_PROTOCOL))
1515 prot = atoi(MAJOR_PROTOCOL);
1517 * Because the previous test is only in 2.10, the following is needed
1518 * till all servers are 2.10:
1520 if (IsServer(cptr) && prot > Protocol(cptr))
1521 prot = Protocol(cptr);
1522 hop = atoi(parv[2]);
1523 start_timestamp = atoi(parv[3]);
1524 timestamp = atoi(parv[4]);
1525 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1526 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1527 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1529 return exit_client_msg(cptr, sptr, &me,
1530 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1532 ircd_strncpy(info, parv[parc - 1], REALLEN);
1533 info[REALLEN] = '\0';
1534 if (prot < atoi(MINOR_PROTOCOL)) {
1535 sendto_ops("Got incompatible protocol version (%s) from %s",
1536 parv[5], cptr->name);
1537 return exit_new_server(cptr, sptr, host, timestamp,
1538 "Incompatible protocol: %s", parv[5]);
1541 * Check for "FRENCH " infection ;-) (actually this should
1542 * be replaced with routine to check the hostname syntax in
1543 * general). [ This check is still needed, even after the parse
1544 * is fixed, because someone can send "SERVER :foo bar " ].
1545 * Also, changed to check other "difficult" characters, now
1546 * that parse lets all through... --msa
1548 if (strlen(host) > HOSTLEN)
1549 host[HOSTLEN] = '\0';
1550 for (ch = host; *ch; ch++)
1551 if (*ch <= ' ' || *ch > '~')
1553 if (*ch || !strchr(host, '.'))
1555 sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
1556 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1562 * A local server introduces a new server behind this link.
1563 * Check if this is allowed according L:, H: and Q: lines.
1565 if (info[0] == '\0')
1566 return exit_client_msg(cptr, cptr, &me,
1567 "No server info specified for %s", host);
1569 * See if the newly found server is behind a guaranteed
1570 * leaf (L-line). If so, close the link.
1572 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1573 (!lhconf->port || (hop > lhconf->port)))
1576 * L: lines normally come in pairs, here we try to
1577 * make sure that the oldest link is squitted, not
1581 if (timestamp <= cptr->serv->timestamp)
1582 LHcptr = 0; /* Kill incoming server */
1584 LHcptr = cptr; /* Squit ourselfs */
1586 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1587 (lhconf->port && (hop > lhconf->port)))
1589 struct Client *ac3ptr;
1591 /* Look for net junction causing this: */
1592 LHcptr = 0; /* incoming server */
1593 if (*parv[5] != 'J') {
1594 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1595 if (IsJunction(ac3ptr)) {
1604 if (IsUnknown(cptr) || IsHandshake(cptr))
1609 * A local link that is still in undefined state wants
1610 * to be a SERVER. Check if this is allowed and change
1611 * status accordingly...
1614 * If there is more then one server on the same machine
1615 * that we try to connect to, it could be that the /CONNECT
1616 * <mask> caused this connect to be put at the wrong place
1617 * in the hashtable. --Run
1618 * Same thing for Unknown connections that first send NICK.
1620 * Better check if the two strings are (caseless) identical
1621 * and not mess with hash internals.
1624 if ((!(EmptyString(cptr->name)))
1625 && (IsUnknown(cptr) || IsHandshake(cptr))
1626 && 0 != ircd_strcmp(cptr->name, host))
1627 hChangeClient(cptr, host);
1628 ircd_strncpy(cptr->name, host, HOSTLEN);
1629 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1630 cptr->hopcount = hop;
1632 /* check connection rules */
1633 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
1634 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
1635 if (crule_eval(cconf->passwd))
1637 ServerStats->is_ref++;
1638 sendto_ops("Refused connection from %s.", cptr->name);
1639 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1643 if (conf_check_server(cptr)) {
1644 ++ServerStats->is_ref;
1645 sendto_ops("Received unauthorized connection from %s.", cptr->name);
1646 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1653 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1654 ++ServerStats->is_ref;
1656 sendto_ops("Access denied. No conf line for server %s", cptr->name);
1657 return exit_client_msg(cptr, cptr, &me,
1658 "Access denied. No conf line for server %s", cptr->name);
1660 sendto_ops("General C/N: line active: No line for server %s", cptr->name);
1662 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1664 sendto_ops("Neither C/N lines for server %s nor "
1665 "\"general.undernet.org\"", cptr->name);
1666 return exit_client_msg(cptr, cptr, &me,
1667 "No C/N lines for server %s", cptr->name);
1669 #endif /* GODMODE */
1671 #ifdef CRYPT_LINK_PASSWORD
1672 /* passwd may be NULL. Head it off at the pass... */
1677 salt[0] = aconf->passwd[0];
1678 salt[1] = aconf->passwd[1];
1680 encr = ircd_crypt(cptr->passwd, salt);
1685 encr = cptr->passwd;
1686 #endif /* CRYPT_LINK_PASSWORD */
1688 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1689 ++ServerStats->is_ref;
1690 sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
1691 return exit_client_msg(cptr, cptr, &me,
1692 "No Access (passwd mismatch) %s", cptr->name);
1694 #endif /* not GODMODE */
1695 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1698 for (i = 0; i <= HighestFd; i++)
1699 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1708 * We want to find IsConnecting() and IsHandshake() too,
1710 * The second finds collisions with numeric representation of existing
1711 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1714 while ((acptr = FindClient(host)) ||
1715 (parc > 7 && (acptr = FindNServer(parv[6]))))
1718 * This link is trying feed me a server that I already have
1719 * access through another path
1721 * Do not allow Uworld to do this.
1722 * Do not allow servers that are juped.
1723 * Do not allow servers that have older link timestamps
1725 * Do not allow servers that use the same numeric as an existing
1726 * server, but have a different name.
1728 * If my ircd.conf sucks, I can try to connect to myself:
1731 return exit_client_msg(cptr, cptr, &me,
1732 "nick collision with me (%s)", host);
1734 * Detect wrong numeric.
1736 if (0 != ircd_strcmp(acptr->name, host))
1738 sendto_serv_butone(cptr,
1739 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1740 me.name, acptr->name, host);
1741 return exit_client_msg(cptr, cptr, &me,
1742 "NUMERIC collision between %s and %s."
1743 " Is your server numeric correct ?", host, acptr->name);
1746 * Kill our try, if we had one.
1748 if (IsConnecting(acptr))
1750 if (!active_lh_line && exit_client(cptr, acptr, &me,
1751 "Just connected via another link") == CPTR_KILLED)
1754 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1755 * 'IsServer', because new 'IsConnecting's are refused to
1756 * the same server if we already had it.
1761 * Avoid other nick collisions...
1762 * This is a doubtfull test though, what else would it be
1763 * when it has a server.name ?
1765 else if (!IsServer(acptr) && !IsHandshake(acptr))
1766 return exit_client_msg(cptr, cptr, &me,
1767 "Nickname %s already exists!", host);
1769 * Our new server might be a juped server,
1770 * or someone trying abuse a second Uworld:
1772 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1773 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1775 if (!IsServer(sptr))
1776 return exit_client(cptr, sptr, &me, acptr->info);
1777 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
1778 me.name, parv[0], parv[1], cptr->name);
1779 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1782 * Of course we find the handshake this link was before :)
1784 else if (IsHandshake(acptr) && acptr == cptr)
1787 * Here we have a server nick collision...
1788 * We don't want to kill the link that was last /connected,
1789 * but we neither want to kill a good (old) link.
1790 * Therefor we kill the second youngest link.
1794 struct Client* c2ptr = 0;
1795 struct Client* c3ptr = acptr;
1796 struct Client* ac2ptr;
1797 struct Client* ac3ptr;
1799 /* Search youngest link: */
1800 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1801 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1805 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1806 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1809 if (timestamp > c3ptr->serv->timestamp)
1812 c2ptr = acptr; /* Make sure they differ */
1814 /* Search second youngest link: */
1815 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1816 if (ac2ptr != c3ptr &&
1817 ac2ptr->serv->timestamp >
1818 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1822 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1823 if (ac2ptr != c3ptr &&
1824 ac2ptr->serv->timestamp >
1825 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1828 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1830 /* If timestamps are equal, decide which link to break
1833 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1834 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1843 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1848 n2up = IsServer(sptr) ? sptr->name : me.name;
1853 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1858 n3up = IsServer(sptr) ? sptr->name : me.name;
1860 if (strcmp(n2, n2up) > 0)
1862 if (strcmp(n3, n3up) > 0)
1864 if (strcmp(n3, n2) > 0)
1871 /* Now squit the second youngest link: */
1873 return exit_new_server(cptr, sptr, host, timestamp,
1874 "server %s already exists and is %ld seconds younger.",
1875 host, (long)acptr->serv->timestamp - (long)timestamp);
1876 else if (c2ptr->from == cptr || IsServer(sptr))
1878 struct Client *killedptrfrom = c2ptr->from;
1882 * If the L: or H: line also gets rid of this link,
1883 * we sent just one squit.
1885 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1888 * If breaking the loop here solves the L: or H:
1889 * line problem, we don't squit that.
1891 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1896 * If we still have a L: or H: line problem,
1897 * we prefer to squit the new server, solving
1898 * loop and L:/H: line problem with only one squit.
1905 * If the new server was introduced by a server that caused a
1906 * Ghost less then 20 seconds ago, this is probably also
1907 * a Ghost... (20 seconds is more then enough because all
1908 * SERVER messages are at the beginning of a net.burst). --Run
1910 if (CurrentTime - cptr->serv->ghost < 20)
1912 killedptrfrom = acptr->from;
1913 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1916 else if (exit_client_msg(cptr, c2ptr, &me,
1917 "Loop <-- %s (new link is %ld seconds younger)", host,
1918 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1919 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1922 * Did we kill the incoming server off already ?
1924 if (killedptrfrom == cptr)
1931 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1933 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1942 * We can't believe it is a lagged server message
1943 * when it directly connects to us...
1944 * kill the older link at the ghost, rather then
1945 * at the second youngest link, assuming it isn't
1948 ghost = CurrentTime; /* Mark that it caused a ghost */
1949 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1959 return exit_new_server(cptr, sptr, host, timestamp,
1960 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1962 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1966 int killed = a_kills_b_too(LHcptr, sptr);
1967 if (active_lh_line < 3)
1969 if (exit_client_msg(cptr, LHcptr, &me,
1970 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1972 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1977 ServerStats->is_ref++;
1978 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1982 * Did we kill the incoming server off already ?
1992 * Server is informing about a new server behind
1993 * this link. Create REMOTE server structure,
1994 * add it to list and propagate word to my other
1998 acptr = make_client(cptr, STAT_SERVER);
2000 acptr->serv->prot = prot;
2001 acptr->serv->timestamp = timestamp;
2002 acptr->hopcount = hop;
2003 ircd_strncpy(acptr->name, host, HOSTLEN);
2004 ircd_strncpy(acptr->info, info, REALLEN);
2005 acptr->serv->up = sptr;
2006 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
2007 /* Use cptr, because we do protocol 9 -> 10 translation
2008 for numeric nicks ! */
2009 SetServerYXX(cptr, acptr, parv[6]);
2011 Count_newremoteserver(UserStats);
2012 if (Protocol(acptr) < 10)
2013 acptr->flags |= FLAGS_TS8;
2014 add_client_to_list(acptr);
2016 if (*parv[5] == 'J')
2019 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
2020 sptr->name, acptr->name);
2024 * Old sendto_serv_but_one() call removed because we now need to send
2025 * different names to different servers (domain name matching).
2027 for (i = 0; i <= HighestFd; i++)
2029 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
2030 bcptr == cptr || IsMe(bcptr))
2032 if (0 == match(me.name, acptr->name))
2034 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
2035 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
2036 NumServCap(acptr), acptr->info);
2041 if (IsUnknown(cptr) || IsHandshake(cptr))
2044 cptr->serv->timestamp = timestamp;
2045 cptr->serv->prot = prot;
2046 cptr->serv->ghost = ghost;
2047 SetServerYXX(cptr, cptr, parv[6]);
2048 if (start_timestamp > OLDEST_TS)
2050 #ifndef RELIABLE_CLOCK
2052 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
2053 TIME_T_FMT, me.serv->timestamp, start_timestamp);
2054 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
2055 TIME_T_FMT " ; difference %ld",
2056 recv_time, timestamp, timestamp - recv_time);
2058 if (start_timestamp < me.serv->timestamp)
2060 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
2061 start_timestamp, me.serv->timestamp);
2062 me.serv->timestamp = start_timestamp;
2063 TSoffset += timestamp - recv_time;
2064 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
2066 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
2067 cptr->serv->timestamp = TStime();
2069 else if (timestamp != recv_time)
2072 * Equal start times, we have a collision. Let the connected-to server
2073 * decide. This assumes leafs issue more than half of the connection
2076 if (IsUnknown(cptr))
2077 cptr->serv->timestamp = TStime();
2078 else if (IsHandshake(cptr))
2080 sendto_ops("clock adjusted by adding %d",
2081 (int)(timestamp - recv_time));
2082 TSoffset += timestamp - recv_time;
2085 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2086 if (start_timestamp < me.serv->timestamp)
2087 me.serv->timestamp = start_timestamp;
2088 if (IsUnknown(cptr))
2089 cptr->serv->timestamp = TStime();
2093 ret = server_estab(cptr, aconf);
2097 #ifdef RELIABLE_CLOCK
2098 if (abs(cptr->serv->timestamp - recv_time) > 30)
2100 sendto_ops("Connected to a net with a timestamp-clock"
2101 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2102 " this.", timestamp - recv_time);
2103 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
2104 me.name, TStime(), me.name);