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;
153 if (IsUserPort(cptr))
154 return exit_client_msg(cptr, cptr, &me,
155 "Cannot connect a server to a user port");
157 recv_time = TStime();
162 return need_more_params(sptr, "SERVER");
163 return exit_client(cptr, cptr, &me, "Need more parameters");
167 if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
168 return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
170 ircd_log(L_NOTICE, "SERVER: %s %s[%s]", parv[1], cptr->sockhost, cptr->sock_ip);
175 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
176 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
178 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
181 prot = atoi(parv[5] + 1);
182 if (prot > atoi(MAJOR_PROTOCOL))
183 prot = atoi(MAJOR_PROTOCOL);
185 * Because the previous test is only in 2.10, the following is needed
186 * till all servers are 2.10:
188 if (IsServer(cptr) && prot > Protocol(cptr))
189 prot = Protocol(cptr);
191 start_timestamp = atoi(parv[3]);
192 timestamp = atoi(parv[4]);
193 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
194 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
196 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
198 return exit_client_msg(cptr, sptr, &me,
199 "Bogus timestamps (%s %s)", parv[3], parv[4]);
201 ircd_strncpy(info, parv[parc - 1], REALLEN);
202 info[REALLEN] = '\0';
203 if (prot < atoi(MINOR_PROTOCOL)) {
204 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
205 "(%s) from %s", parv[5], cptr->name);
206 return exit_new_server(cptr, sptr, host, timestamp,
207 "Incompatible protocol: %s", parv[5]);
210 * Check for "FRENCH " infection ;-) (actually this should
211 * be replaced with routine to check the hostname syntax in
212 * general). [ This check is still needed, even after the parse
213 * is fixed, because someone can send "SERVER :foo bar " ].
214 * Also, changed to check other "difficult" characters, now
215 * that parse lets all through... --msa
217 if (strlen(host) > HOSTLEN)
218 host[HOSTLEN] = '\0';
220 for (ch = host; *ch; ch++) {
221 if (*ch <= ' ' || *ch > '~')
224 if (*ch || !strchr(host, '.')) {
225 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
227 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
233 * A local server introduces a new server behind this link.
234 * Check if this is allowed according L:, H: and Q: lines.
237 return exit_client_msg(cptr, cptr, &me,
238 "No server info specified for %s", host);
240 * See if the newly found server is behind a guaranteed
241 * leaf (L-line). If so, close the link.
243 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
244 (!lhconf->port || (hop > lhconf->port)))
247 * L: lines normally come in pairs, here we try to
248 * make sure that the oldest link is squitted, not
252 if (timestamp <= cptr->serv->timestamp)
253 LHcptr = 0; /* Kill incoming server */
255 LHcptr = cptr; /* Squit ourselfs */
257 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
258 (lhconf->port && (hop > lhconf->port)))
260 struct Client *ac3ptr;
262 /* Look for net junction causing this: */
263 LHcptr = 0; /* incoming server */
264 if (*parv[5] != 'J') {
265 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
266 if (IsJunction(ac3ptr)) {
275 if (IsUnknown(cptr) || IsHandshake(cptr))
280 * A local link that is still in undefined state wants
281 * to be a SERVER. Check if this is allowed and change
282 * status accordingly...
285 * If there is more then one server on the same machine
286 * that we try to connect to, it could be that the /CONNECT
287 * <mask> caused this connect to be put at the wrong place
288 * in the hashtable. --Run
289 * Same thing for Unknown connections that first send NICK.
291 * Better check if the two strings are (caseless) identical
292 * and not mess with hash internals.
295 if (!EmptyString(cptr->name) &&
296 (IsUnknown(cptr) || IsHandshake(cptr)) &&
297 0 != ircd_strcmp(cptr->name, host))
298 hChangeClient(cptr, host);
299 ircd_strncpy(cptr->name, host, HOSTLEN);
300 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
301 cptr->hopcount = hop;
303 /* check connection rules */
304 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
305 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
306 if (crule_eval(cconf->passwd)) {
307 ServerStats->is_ref++;
308 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.",
310 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
314 if (conf_check_server(cptr)) {
315 ++ServerStats->is_ref;
316 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
317 "from %s.", cptr->name);
318 return exit_client(cptr, cptr, &me, "No C:line");
325 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
326 ++ServerStats->is_ref;
328 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
329 "server %s", cptr->name);
330 return exit_client_msg(cptr, cptr, &me,
331 "Access denied. No conf line for server %s", cptr->name);
333 sendto_opmask_butone(0, SNO_OLDSNO, "General C: line active: No line "
334 "for server %s", cptr->name);
335 aconf = find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
337 sendto_opmask_butone(0, SNO_OLDSNO, "Neither C lines for server %s "
338 "nor \"general.undernet.org\"", cptr->name);
339 return exit_client_msg(cptr, cptr, &me, "No C lines for server %s", cptr->name);
343 #ifdef CRYPT_LINK_PASSWORD
344 /* passwd may be NULL. Head it off at the pass... */
348 salt[0] = aconf->passwd[0];
349 salt[1] = aconf->passwd[1];
351 encr = ircd_crypt(cptr->passwd, salt);
357 #endif /* CRYPT_LINK_PASSWORD */
359 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
360 ++ServerStats->is_ref;
361 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
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 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
409 ":SERVER Numeric Collision: %s != %s",
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 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
448 ":Received :%s SERVER %s from %s !?!", parv[0],
449 parv[1], cptr->name);
450 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
453 * Of course we find the handshake this link was before :)
455 else if (IsHandshake(acptr) && acptr == cptr)
458 * Here we have a server nick collision...
459 * We don't want to kill the link that was last /connected,
460 * but we neither want to kill a good (old) link.
461 * Therefor we kill the second youngest link.
465 struct Client* c2ptr = 0;
466 struct Client* c3ptr = acptr;
467 struct Client* ac2ptr;
468 struct Client* ac3ptr;
470 /* Search youngest link: */
471 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
472 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
476 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
477 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
480 if (timestamp > c3ptr->serv->timestamp)
483 c2ptr = acptr; /* Make sure they differ */
485 /* Search second youngest link: */
486 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
487 if (ac2ptr != c3ptr &&
488 ac2ptr->serv->timestamp >
489 (c2ptr ? c2ptr->serv->timestamp : timestamp))
493 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
494 if (ac2ptr != c3ptr &&
495 ac2ptr->serv->timestamp >
496 (c2ptr ? c2ptr->serv->timestamp : timestamp))
499 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
501 /* If timestamps are equal, decide which link to break
504 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
505 (c3ptr ? c3ptr->serv->timestamp : timestamp))
514 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
519 n2up = IsServer(sptr) ? sptr->name : me.name;
524 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
529 n3up = IsServer(sptr) ? sptr->name : me.name;
531 if (strcmp(n2, n2up) > 0)
533 if (strcmp(n3, n3up) > 0)
535 if (strcmp(n3, n2) > 0)
542 /* Now squit the second youngest link: */
544 return exit_new_server(cptr, sptr, host, timestamp,
545 "server %s already exists and is %ld seconds younger.",
546 host, (long)acptr->serv->timestamp - (long)timestamp);
547 else if (c2ptr->from == cptr || IsServer(sptr))
549 struct Client *killedptrfrom = c2ptr->from;
553 * If the L: or H: line also gets rid of this link,
554 * we sent just one squit.
556 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
559 * If breaking the loop here solves the L: or H:
560 * line problem, we don't squit that.
562 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
567 * If we still have a L: or H: line problem,
568 * we prefer to squit the new server, solving
569 * loop and L:/H: line problem with only one squit.
576 * If the new server was introduced by a server that caused a
577 * Ghost less then 20 seconds ago, this is probably also
578 * a Ghost... (20 seconds is more then enough because all
579 * SERVER messages are at the beginning of a net.burst). --Run
581 if (CurrentTime - cptr->serv->ghost < 20)
583 killedptrfrom = acptr->from;
584 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
587 else if (exit_client_msg(cptr, c2ptr, &me,
588 "Loop <-- %s (new link is %ld seconds younger)", host,
589 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
590 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
593 * Did we kill the incoming server off already ?
595 if (killedptrfrom == cptr)
602 if (LHcptr && a_kills_b_too(LHcptr, acptr))
604 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
613 * We can't believe it is a lagged server message
614 * when it directly connects to us...
615 * kill the older link at the ghost, rather then
616 * at the second youngest link, assuming it isn't
619 ghost = CurrentTime; /* Mark that it caused a ghost */
620 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
630 return exit_new_server(cptr, sptr, host, timestamp,
631 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
632 "Leaf-only link %s <- %s(%s), check L:",
634 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
638 int killed = a_kills_b_too(LHcptr, sptr);
639 if (active_lh_line < 3)
641 if (exit_client_msg(cptr, LHcptr, &me,
642 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
643 "Leaf-only link %s <- %s(%s), check L:",
645 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
650 ServerStats->is_ref++;
651 if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
655 * Did we kill the incoming server off already ?
665 * Server is informing about a new server behind
666 * this link. Create REMOTE server structure,
667 * add it to list and propagate word to my other
671 acptr = make_client(cptr, STAT_SERVER);
673 acptr->serv->prot = prot;
674 acptr->serv->timestamp = timestamp;
675 acptr->hopcount = hop;
676 ircd_strncpy(acptr->name, host, HOSTLEN);
677 ircd_strncpy(acptr->info, info, REALLEN);
678 acptr->serv->up = sptr;
679 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
680 /* Use cptr, because we do protocol 9 -> 10 translation
681 for numeric nicks ! */
682 SetServerYXX(cptr, acptr, parv[6]);
684 Count_newremoteserver(UserStats);
685 if (Protocol(acptr) < 10)
686 acptr->flags |= FLAGS_TS8;
687 add_client_to_list(acptr);
692 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
693 sptr->name, acptr->name);
697 * Old sendto_serv_but_one() call removed because we now need to send
698 * different names to different servers (domain name matching).
700 * Personally, I think this is bogus; it's a feature we don't use here.
703 for (i = 0; i <= HighestFd; i++)
705 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
706 bcptr == cptr || IsMe(bcptr))
708 if (0 == match(me.name, acptr->name))
710 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
711 acptr->name, hop + 1, parv[4], parv[5], NumServCap(acptr),
717 if (IsUnknown(cptr) || IsHandshake(cptr))
720 cptr->serv->timestamp = timestamp;
721 cptr->serv->prot = prot;
722 cptr->serv->ghost = ghost;
723 SetServerYXX(cptr, cptr, parv[6]);
724 if (start_timestamp > OLDEST_TS)
726 #ifndef RELIABLE_CLOCK
728 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
729 "others start time: %Tu", me.serv->timestamp,
731 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
732 "received timestamp: %Tu ; difference %ld",
733 recv_time, timestamp, timestamp - recv_time);
735 if (start_timestamp < me.serv->timestamp)
737 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
738 "%Tu < %Tu", start_timestamp, me.serv->timestamp);
739 me.serv->timestamp = start_timestamp;
740 TSoffset += timestamp - recv_time;
741 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
742 (int)(timestamp - recv_time));
744 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
745 cptr->serv->timestamp = TStime();
747 else if (timestamp != recv_time)
750 * Equal start times, we have a collision. Let the connected-to server
751 * decide. This assumes leafs issue more than half of the connection
755 cptr->serv->timestamp = TStime();
756 else if (IsHandshake(cptr))
758 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
759 (int)(timestamp - recv_time));
760 TSoffset += timestamp - recv_time;
763 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
764 if (start_timestamp < me.serv->timestamp)
765 me.serv->timestamp = start_timestamp;
767 cptr->serv->timestamp = TStime();
771 ret = server_estab(cptr, aconf);
775 #ifdef RELIABLE_CLOCK
776 if (abs(cptr->serv->timestamp - recv_time) > 30)
778 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
779 "timestamp-clock difference of %Td seconds! "
780 "Used SETTIME to correct this.",
781 timestamp - recv_time);
782 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), me.name);
790 * ms_server - server message handler
792 * parv[0] = sender prefix
793 * parv[1] = servername
795 * parv[3] = start timestamp
796 * parv[4] = link timestamp
797 * parv[5] = major protocol version: P09/P10
798 * parv[parc-1] = serverinfo
800 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
801 * numeric nick mask of this server.
802 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
804 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
808 char info[REALLEN + 1];
810 struct Client* acptr;
811 struct Client* bcptr;
812 struct Client* LHcptr = 0;
813 struct ConfItem* aconf = 0;
814 struct ConfItem* cconf;
815 struct ConfItem* lhconf = 0;
816 struct Jupe* ajupe = 0;
819 int active_lh_line = 0;
821 time_t start_timestamp;
822 time_t timestamp = 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_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
874 "(%s) from %s", 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_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
894 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
900 * A local server introduces a new server behind this link.
901 * Check if this is allowed according L:, H: and Q: lines.
904 return exit_client_msg(cptr, cptr, &me,
905 "No server info specified for %s", host);
907 * See if the newly found server is behind a guaranteed
908 * leaf (L-line). If so, close the link.
910 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
911 (!lhconf->port || (hop > lhconf->port)))
914 * L: lines normally come in pairs, here we try to
915 * make sure that the oldest link is squitted, not
919 if (timestamp <= cptr->serv->timestamp)
920 LHcptr = 0; /* Kill incoming server */
922 LHcptr = cptr; /* Squit ourselfs */
924 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
925 (lhconf->port && (hop > lhconf->port)))
927 struct Client *ac3ptr;
929 /* Look for net junction causing this: */
930 LHcptr = 0; /* incoming server */
931 if (*parv[5] != 'J') {
932 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
933 if (IsJunction(ac3ptr)) {
942 if (IsUnknown(cptr) || IsHandshake(cptr))
947 * A local link that is still in undefined state wants
948 * to be a SERVER. Check if this is allowed and change
949 * status accordingly...
952 * If there is more then one server on the same machine
953 * that we try to connect to, it could be that the /CONNECT
954 * <mask> caused this connect to be put at the wrong place
955 * in the hashtable. --Run
956 * Same thing for Unknown connections that first send NICK.
958 * Better check if the two strings are (caseless) identical
959 * and not mess with hash internals.
962 if ((!(EmptyString(cptr->name)))
963 && (IsUnknown(cptr) || IsHandshake(cptr))
964 && 0 != ircd_strcmp(cptr->name, host))
965 hChangeClient(cptr, host);
966 ircd_strncpy(cptr->name, host, HOSTLEN);
967 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
968 cptr->hopcount = hop;
970 /* check connection rules */
971 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
972 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
973 if (crule_eval(cconf->passwd))
975 ServerStats->is_ref++;
976 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.",
978 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
982 if (conf_check_server(cptr)) {
983 ++ServerStats->is_ref;
984 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
985 "from %s.", cptr->name);
986 return exit_client(cptr, cptr, &me, "No C conf lines");
993 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
994 ++ServerStats->is_ref;
996 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
997 "server %s", cptr->name);
998 return exit_client_msg(cptr, cptr, &me,
999 "Access denied. No conf line for server %s", cptr->name);
1001 sendto_opmask_butone(0, SNO_OLDSNO, "General C line active: No line "
1002 "for server %s", cptr->name);
1004 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1006 sendto_opmask_butone(0, SNO_OLDSNO, "Neither C lines for server %s "
1007 "nor \"general.undernet.org\"", cptr->name);
1008 return exit_client_msg(cptr, cptr, &me,
1009 "No C lines for server %s", cptr->name);
1011 #endif /* GODMODE */
1013 #ifdef CRYPT_LINK_PASSWORD
1014 /* passwd may be NULL. Head it off at the pass... */
1019 salt[0] = aconf->passwd[0];
1020 salt[1] = aconf->passwd[1];
1022 encr = ircd_crypt(cptr->passwd, salt);
1027 encr = cptr->passwd;
1028 #endif /* CRYPT_LINK_PASSWORD */
1030 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1031 ++ServerStats->is_ref;
1032 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
1034 return exit_client_msg(cptr, cptr, &me,
1035 "No Access (passwd mismatch) %s", cptr->name);
1037 #endif /* not GODMODE */
1038 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1041 for (i = 0; i <= HighestFd; i++)
1042 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1051 * We want to find IsConnecting() and IsHandshake() too,
1053 * The second finds collisions with numeric representation of existing
1054 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1057 while ((acptr = FindClient(host)) ||
1058 (parc > 7 && (acptr = FindNServer(parv[6]))))
1061 * This link is trying feed me a server that I already have
1062 * access through another path
1064 * Do not allow Uworld to do this.
1065 * Do not allow servers that are juped.
1066 * Do not allow servers that have older link timestamps
1068 * Do not allow servers that use the same numeric as an existing
1069 * server, but have a different name.
1071 * If my ircd.conf sucks, I can try to connect to myself:
1074 return exit_client_msg(cptr, cptr, &me,
1075 "nick collision with me, check server number in M:? (%s)", host);
1077 * Detect wrong numeric.
1079 if (0 != ircd_strcmp(acptr->name, host))
1081 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1082 ":SERVER Numeric Collision: %s != %s", acptr->name,
1084 return exit_client_msg(cptr, cptr, &me,
1085 "NUMERIC collision between %s and %s."
1086 " Is your server numeric correct ?", host, acptr->name);
1089 * Kill our try, if we had one.
1091 if (IsConnecting(acptr))
1093 if (!active_lh_line && exit_client(cptr, acptr, &me,
1094 "Just connected via another link") == CPTR_KILLED)
1097 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1098 * 'IsServer', because new 'IsConnecting's are refused to
1099 * the same server if we already had it.
1104 * Avoid other nick collisions...
1105 * This is a doubtfull test though, what else would it be
1106 * when it has a server.name ?
1108 else if (!IsServer(acptr) && !IsHandshake(acptr))
1109 return exit_client_msg(cptr, cptr, &me,
1110 "Nickname %s already exists!", host);
1112 * Our new server might be a juped server,
1113 * or someone trying abuse a second Uworld:
1115 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1116 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1118 if (!IsServer(sptr))
1119 return exit_client(cptr, sptr, &me, acptr->info);
1120 sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1121 "from %s !?!", parv[0], parv[1], cptr->name);
1122 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1125 * Of course we find the handshake this link was before :)
1127 else if (IsHandshake(acptr) && acptr == cptr)
1130 * Here we have a server nick collision...
1131 * We don't want to kill the link that was last /connected,
1132 * but we neither want to kill a good (old) link.
1133 * Therefor we kill the second youngest link.
1137 struct Client* c2ptr = 0;
1138 struct Client* c3ptr = acptr;
1139 struct Client* ac2ptr;
1140 struct Client* ac3ptr;
1142 /* Search youngest link: */
1143 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1144 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1148 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1149 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1152 if (timestamp > c3ptr->serv->timestamp)
1155 c2ptr = acptr; /* Make sure they differ */
1157 /* Search second youngest link: */
1158 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1159 if (ac2ptr != c3ptr &&
1160 ac2ptr->serv->timestamp >
1161 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1165 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1166 if (ac2ptr != c3ptr &&
1167 ac2ptr->serv->timestamp >
1168 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1171 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1173 /* If timestamps are equal, decide which link to break
1176 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1177 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1186 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1191 n2up = IsServer(sptr) ? sptr->name : me.name;
1196 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1201 n3up = IsServer(sptr) ? sptr->name : me.name;
1203 if (strcmp(n2, n2up) > 0)
1205 if (strcmp(n3, n3up) > 0)
1207 if (strcmp(n3, n2) > 0)
1214 /* Now squit the second youngest link: */
1216 return exit_new_server(cptr, sptr, host, timestamp,
1217 "server %s already exists and is %ld seconds younger.",
1218 host, (long)acptr->serv->timestamp - (long)timestamp);
1219 else if (c2ptr->from == cptr || IsServer(sptr))
1221 struct Client *killedptrfrom = c2ptr->from;
1225 * If the L: or H: line also gets rid of this link,
1226 * we sent just one squit.
1228 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1231 * If breaking the loop here solves the L: or H:
1232 * line problem, we don't squit that.
1234 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1239 * If we still have a L: or H: line problem,
1240 * we prefer to squit the new server, solving
1241 * loop and L:/H: line problem with only one squit.
1248 * If the new server was introduced by a server that caused a
1249 * Ghost less then 20 seconds ago, this is probably also
1250 * a Ghost... (20 seconds is more then enough because all
1251 * SERVER messages are at the beginning of a net.burst). --Run
1253 if (CurrentTime - cptr->serv->ghost < 20)
1255 killedptrfrom = acptr->from;
1256 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1259 else if (exit_client_msg(cptr, c2ptr, &me,
1260 "Loop <-- %s (new link is %ld seconds younger)", host,
1261 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1262 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1265 * Did we kill the incoming server off already ?
1267 if (killedptrfrom == cptr)
1274 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1276 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1285 * We can't believe it is a lagged server message
1286 * when it directly connects to us...
1287 * kill the older link at the ghost, rather then
1288 * at the second youngest link, assuming it isn't
1291 ghost = CurrentTime; /* Mark that it caused a ghost */
1292 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1302 return exit_new_server(cptr, sptr, host, timestamp,
1303 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1305 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1309 int killed = a_kills_b_too(LHcptr, sptr);
1310 if (active_lh_line < 3)
1312 if (exit_client_msg(cptr, LHcptr, &me,
1313 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1315 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1320 ServerStats->is_ref++;
1321 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1325 * Did we kill the incoming server off already ?
1335 * Server is informing about a new server behind
1336 * this link. Create REMOTE server structure,
1337 * add it to list and propagate word to my other
1341 acptr = make_client(cptr, STAT_SERVER);
1343 acptr->serv->prot = prot;
1344 acptr->serv->timestamp = timestamp;
1345 acptr->hopcount = hop;
1346 ircd_strncpy(acptr->name, host, HOSTLEN);
1347 ircd_strncpy(acptr->info, info, REALLEN);
1348 acptr->serv->up = sptr;
1349 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1350 /* Use cptr, because we do protocol 9 -> 10 translation
1351 for numeric nicks ! */
1352 SetServerYXX(cptr, acptr, parv[6]);
1354 Count_newremoteserver(UserStats);
1355 if (Protocol(acptr) < 10)
1356 acptr->flags |= FLAGS_TS8;
1357 add_client_to_list(acptr);
1359 if (*parv[5] == 'J')
1362 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1363 sptr->name, acptr->name);
1367 * Old sendto_serv_but_one() call removed because we now need to send
1368 * different names to different servers (domain name matching).
1370 for (i = 0; i <= HighestFd; i++)
1372 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1373 bcptr == cptr || IsMe(bcptr))
1375 if (0 == match(me.name, acptr->name))
1377 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1378 acptr->name, hop + 1, parv[4], parv[5], NumServCap(acptr),
1384 if (IsUnknown(cptr) || IsHandshake(cptr))
1387 cptr->serv->timestamp = timestamp;
1388 cptr->serv->prot = prot;
1389 cptr->serv->ghost = ghost;
1390 SetServerYXX(cptr, cptr, parv[6]);
1391 if (start_timestamp > OLDEST_TS)
1393 #ifndef RELIABLE_CLOCK
1395 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
1396 "others start time: %Tu", me.serv->timestamp,
1398 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
1399 "received timestamp: %Tu ; difference %ld",
1400 recv_time, timestamp, timestamp - recv_time);
1402 if (start_timestamp < me.serv->timestamp)
1404 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1405 "%Tu < %Tu", start_timestamp, me.serv->timestamp);
1406 me.serv->timestamp = start_timestamp;
1407 TSoffset += timestamp - recv_time;
1408 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1409 (int)(timestamp - recv_time));
1411 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1412 cptr->serv->timestamp = TStime();
1414 else if (timestamp != recv_time)
1417 * Equal start times, we have a collision. Let the connected-to server
1418 * decide. This assumes leafs issue more than half of the connection
1421 if (IsUnknown(cptr))
1422 cptr->serv->timestamp = TStime();
1423 else if (IsHandshake(cptr))
1425 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1426 (int)(timestamp - recv_time));
1427 TSoffset += timestamp - recv_time;
1430 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
1431 if (start_timestamp < me.serv->timestamp)
1432 me.serv->timestamp = start_timestamp;
1433 if (IsUnknown(cptr))
1434 cptr->serv->timestamp = TStime();
1438 ret = server_estab(cptr, aconf);
1442 #ifdef RELIABLE_CLOCK
1443 if (abs(cptr->serv->timestamp - recv_time) > 30)
1445 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1446 "timestamp-clock difference of %Td seconds! Used "
1447 "SETTIME to correct this.", timestamp - recv_time);
1448 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), me.name);
1460 * parv[0] = sender prefix
1461 * parv[1] = servername
1462 * parv[2] = hopcount
1463 * parv[3] = start timestamp
1464 * parv[4] = link timestamp
1465 * parv[5] = major protocol version: P09/P10
1466 * parv[parc-1] = serverinfo
1468 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1469 * numeric nick mask of this server.
1470 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1472 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1476 char info[REALLEN + 1];
1478 struct Client* acptr;
1479 struct Client* bcptr;
1480 struct Client* LHcptr = 0;
1481 struct ConfItem* aconf = 0;
1482 struct ConfItem* cconf;
1483 struct ConfItem* lhconf = 0;
1484 struct Jupe* ajupe = 0;
1487 int active_lh_line = 0;
1488 unsigned short prot;
1489 time_t start_timestamp;
1490 time_t timestamp = 0;
1496 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1500 if (IsUserPort(cptr))
1501 return exit_client_msg(cptr, cptr, &me,
1502 "You cannot connect a server to a user port; connect to %s port %u",
1503 me.name, server_port);
1505 recv_time = TStime();
1509 return need_more_params(sptr, "SERVER");
1510 return exit_client(cptr, cptr, &me, "Need more parameters");
1516 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1517 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1519 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1522 prot = atoi(parv[5] + 1);
1523 if (prot > atoi(MAJOR_PROTOCOL))
1524 prot = atoi(MAJOR_PROTOCOL);
1526 * Because the previous test is only in 2.10, the following is needed
1527 * till all servers are 2.10:
1529 if (IsServer(cptr) && prot > Protocol(cptr))
1530 prot = Protocol(cptr);
1531 hop = atoi(parv[2]);
1532 start_timestamp = atoi(parv[3]);
1533 timestamp = atoi(parv[4]);
1534 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1535 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1536 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1538 return exit_client_msg(cptr, sptr, &me,
1539 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1541 ircd_strncpy(info, parv[parc - 1], REALLEN);
1542 info[REALLEN] = '\0';
1543 if (prot < atoi(MINOR_PROTOCOL)) {
1544 sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1545 parv[5], cptr->name);
1546 return exit_new_server(cptr, sptr, host, timestamp,
1547 "Incompatible protocol: %s", parv[5]);
1550 * Check for "FRENCH " infection ;-) (actually this should
1551 * be replaced with routine to check the hostname syntax in
1552 * general). [ This check is still needed, even after the parse
1553 * is fixed, because someone can send "SERVER :foo bar " ].
1554 * Also, changed to check other "difficult" characters, now
1555 * that parse lets all through... --msa
1557 if (strlen(host) > HOSTLEN)
1558 host[HOSTLEN] = '\0';
1559 for (ch = host; *ch; ch++)
1560 if (*ch <= ' ' || *ch > '~')
1562 if (*ch || !strchr(host, '.'))
1564 sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1565 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1571 * A local server introduces a new server behind this link.
1572 * Check if this is allowed according L:, H: and Q: lines.
1574 if (info[0] == '\0')
1575 return exit_client_msg(cptr, cptr, &me,
1576 "No server info specified for %s", host);
1578 * See if the newly found server is behind a guaranteed
1579 * leaf (L-line). If so, close the link.
1581 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1582 (!lhconf->port || (hop > lhconf->port)))
1585 * L: lines normally come in pairs, here we try to
1586 * make sure that the oldest link is squitted, not
1590 if (timestamp <= cptr->serv->timestamp)
1591 LHcptr = 0; /* Kill incoming server */
1593 LHcptr = cptr; /* Squit ourselfs */
1595 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1596 (lhconf->port && (hop > lhconf->port)))
1598 struct Client *ac3ptr;
1600 /* Look for net junction causing this: */
1601 LHcptr = 0; /* incoming server */
1602 if (*parv[5] != 'J') {
1603 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1604 if (IsJunction(ac3ptr)) {
1613 if (IsUnknown(cptr) || IsHandshake(cptr))
1618 * A local link that is still in undefined state wants
1619 * to be a SERVER. Check if this is allowed and change
1620 * status accordingly...
1623 * If there is more then one server on the same machine
1624 * that we try to connect to, it could be that the /CONNECT
1625 * <mask> caused this connect to be put at the wrong place
1626 * in the hashtable. --Run
1627 * Same thing for Unknown connections that first send NICK.
1629 * Better check if the two strings are (caseless) identical
1630 * and not mess with hash internals.
1633 if ((!(EmptyString(cptr->name)))
1634 && (IsUnknown(cptr) || IsHandshake(cptr))
1635 && 0 != ircd_strcmp(cptr->name, host))
1636 hChangeClient(cptr, host);
1637 ircd_strncpy(cptr->name, host, HOSTLEN);
1638 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1639 cptr->hopcount = hop;
1641 /* check connection rules */
1642 for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
1643 if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
1644 if (crule_eval(cconf->passwd))
1646 ServerStats->is_ref++;
1647 sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1648 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1652 if (conf_check_server(cptr)) {
1653 ++ServerStats->is_ref;
1654 sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1655 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1662 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1663 ++ServerStats->is_ref;
1665 sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1666 return exit_client_msg(cptr, cptr, &me,
1667 "Access denied. No conf line for server %s", cptr->name);
1669 sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1671 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1673 sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1674 "\"general.undernet.org\"", cptr->name);
1675 return exit_client_msg(cptr, cptr, &me,
1676 "No C/N lines for server %s", cptr->name);
1678 #endif /* GODMODE */
1680 #ifdef CRYPT_LINK_PASSWORD
1681 /* passwd may be NULL. Head it off at the pass... */
1686 salt[0] = aconf->passwd[0];
1687 salt[1] = aconf->passwd[1];
1689 encr = ircd_crypt(cptr->passwd, salt);
1694 encr = cptr->passwd;
1695 #endif /* CRYPT_LINK_PASSWORD */
1697 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1698 ++ServerStats->is_ref;
1699 sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1700 return exit_client_msg(cptr, cptr, &me,
1701 "No Access (passwd mismatch) %s", cptr->name);
1703 #endif /* not GODMODE */
1704 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1707 for (i = 0; i <= HighestFd; i++)
1708 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1717 * We want to find IsConnecting() and IsHandshake() too,
1719 * The second finds collisions with numeric representation of existing
1720 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1723 while ((acptr = FindClient(host)) ||
1724 (parc > 7 && (acptr = FindNServer(parv[6]))))
1727 * This link is trying feed me a server that I already have
1728 * access through another path
1730 * Do not allow Uworld to do this.
1731 * Do not allow servers that are juped.
1732 * Do not allow servers that have older link timestamps
1734 * Do not allow servers that use the same numeric as an existing
1735 * server, but have a different name.
1737 * If my ircd.conf sucks, I can try to connect to myself:
1740 return exit_client_msg(cptr, cptr, &me,
1741 "nick collision with me, check server number in M:? (%s)", host);
1743 * Detect wrong numeric.
1745 if (0 != ircd_strcmp(acptr->name, host))
1747 sendto_serv_butone(cptr, /* XXX DEAD */
1748 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1749 me.name, acptr->name, host);
1750 return exit_client_msg(cptr, cptr, &me,
1751 "NUMERIC collision between %s and %s."
1752 " Is your server numeric correct ?", host, acptr->name);
1755 * Kill our try, if we had one.
1757 if (IsConnecting(acptr))
1759 if (!active_lh_line && exit_client(cptr, acptr, &me,
1760 "Just connected via another link") == CPTR_KILLED)
1763 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1764 * 'IsServer', because new 'IsConnecting's are refused to
1765 * the same server if we already had it.
1770 * Avoid other nick collisions...
1771 * This is a doubtfull test though, what else would it be
1772 * when it has a server.name ?
1774 else if (!IsServer(acptr) && !IsHandshake(acptr))
1775 return exit_client_msg(cptr, cptr, &me,
1776 "Nickname %s already exists!", host);
1778 * Our new server might be a juped server,
1779 * or someone trying abuse a second Uworld:
1781 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1782 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1784 if (!IsServer(sptr))
1785 return exit_client(cptr, sptr, &me, acptr->info);
1786 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1787 me.name, parv[0], parv[1], cptr->name);
1788 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1791 * Of course we find the handshake this link was before :)
1793 else if (IsHandshake(acptr) && acptr == cptr)
1796 * Here we have a server nick collision...
1797 * We don't want to kill the link that was last /connected,
1798 * but we neither want to kill a good (old) link.
1799 * Therefor we kill the second youngest link.
1803 struct Client* c2ptr = 0;
1804 struct Client* c3ptr = acptr;
1805 struct Client* ac2ptr;
1806 struct Client* ac3ptr;
1808 /* Search youngest link: */
1809 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1810 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1814 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1815 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1818 if (timestamp > c3ptr->serv->timestamp)
1821 c2ptr = acptr; /* Make sure they differ */
1823 /* Search second youngest link: */
1824 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1825 if (ac2ptr != c3ptr &&
1826 ac2ptr->serv->timestamp >
1827 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1831 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1832 if (ac2ptr != c3ptr &&
1833 ac2ptr->serv->timestamp >
1834 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1837 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1839 /* If timestamps are equal, decide which link to break
1842 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1843 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1852 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1857 n2up = IsServer(sptr) ? sptr->name : me.name;
1862 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1867 n3up = IsServer(sptr) ? sptr->name : me.name;
1869 if (strcmp(n2, n2up) > 0)
1871 if (strcmp(n3, n3up) > 0)
1873 if (strcmp(n3, n2) > 0)
1880 /* Now squit the second youngest link: */
1882 return exit_new_server(cptr, sptr, host, timestamp,
1883 "server %s already exists and is %ld seconds younger.",
1884 host, (long)acptr->serv->timestamp - (long)timestamp);
1885 else if (c2ptr->from == cptr || IsServer(sptr))
1887 struct Client *killedptrfrom = c2ptr->from;
1891 * If the L: or H: line also gets rid of this link,
1892 * we sent just one squit.
1894 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1897 * If breaking the loop here solves the L: or H:
1898 * line problem, we don't squit that.
1900 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1905 * If we still have a L: or H: line problem,
1906 * we prefer to squit the new server, solving
1907 * loop and L:/H: line problem with only one squit.
1914 * If the new server was introduced by a server that caused a
1915 * Ghost less then 20 seconds ago, this is probably also
1916 * a Ghost... (20 seconds is more then enough because all
1917 * SERVER messages are at the beginning of a net.burst). --Run
1919 if (CurrentTime - cptr->serv->ghost < 20)
1921 killedptrfrom = acptr->from;
1922 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1925 else if (exit_client_msg(cptr, c2ptr, &me,
1926 "Loop <-- %s (new link is %ld seconds younger)", host,
1927 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1928 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1931 * Did we kill the incoming server off already ?
1933 if (killedptrfrom == cptr)
1940 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1942 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1951 * We can't believe it is a lagged server message
1952 * when it directly connects to us...
1953 * kill the older link at the ghost, rather then
1954 * at the second youngest link, assuming it isn't
1957 ghost = CurrentTime; /* Mark that it caused a ghost */
1958 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1968 return exit_new_server(cptr, sptr, host, timestamp,
1969 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1971 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1975 int killed = a_kills_b_too(LHcptr, sptr);
1976 if (active_lh_line < 3)
1978 if (exit_client_msg(cptr, LHcptr, &me,
1979 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1981 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1986 ServerStats->is_ref++;
1987 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1991 * Did we kill the incoming server off already ?
2001 * Server is informing about a new server behind
2002 * this link. Create REMOTE server structure,
2003 * add it to list and propagate word to my other
2007 acptr = make_client(cptr, STAT_SERVER);
2009 acptr->serv->prot = prot;
2010 acptr->serv->timestamp = timestamp;
2011 acptr->hopcount = hop;
2012 ircd_strncpy(acptr->name, host, HOSTLEN);
2013 ircd_strncpy(acptr->info, info, REALLEN);
2014 acptr->serv->up = sptr;
2015 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
2016 /* Use cptr, because we do protocol 9 -> 10 translation
2017 for numeric nicks ! */
2018 SetServerYXX(cptr, acptr, parv[6]);
2020 Count_newremoteserver(UserStats);
2021 if (Protocol(acptr) < 10)
2022 acptr->flags |= FLAGS_TS8;
2023 add_client_to_list(acptr);
2025 if (*parv[5] == 'J')
2028 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
2029 sptr->name, acptr->name);
2033 * Old sendto_serv_but_one() call removed because we now need to send
2034 * different names to different servers (domain name matching).
2036 for (i = 0; i <= HighestFd; i++)
2038 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
2039 bcptr == cptr || IsMe(bcptr))
2041 if (0 == match(me.name, acptr->name))
2043 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
2044 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
2045 NumServCap(acptr), acptr->info);
2050 if (IsUnknown(cptr) || IsHandshake(cptr))
2053 cptr->serv->timestamp = timestamp;
2054 cptr->serv->prot = prot;
2055 cptr->serv->ghost = ghost;
2056 SetServerYXX(cptr, cptr, parv[6]);
2057 if (start_timestamp > OLDEST_TS)
2059 #ifndef RELIABLE_CLOCK
2061 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
2062 TIME_T_FMT, me.serv->timestamp, start_timestamp);
2063 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
2064 TIME_T_FMT " ; difference %ld",
2065 recv_time, timestamp, timestamp - recv_time);
2067 if (start_timestamp < me.serv->timestamp)
2069 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
2070 start_timestamp, me.serv->timestamp);
2071 me.serv->timestamp = start_timestamp;
2072 TSoffset += timestamp - recv_time;
2073 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
2075 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
2076 cptr->serv->timestamp = TStime();
2078 else if (timestamp != recv_time)
2081 * Equal start times, we have a collision. Let the connected-to server
2082 * decide. This assumes leafs issue more than half of the connection
2085 if (IsUnknown(cptr))
2086 cptr->serv->timestamp = TStime();
2087 else if (IsHandshake(cptr))
2089 sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
2090 (int)(timestamp - recv_time));
2091 TSoffset += timestamp - recv_time;
2094 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2095 if (start_timestamp < me.serv->timestamp)
2096 me.serv->timestamp = start_timestamp;
2097 if (IsUnknown(cptr))
2098 cptr->serv->timestamp = TStime();
2102 ret = server_estab(cptr, aconf);
2106 #ifdef RELIABLE_CLOCK
2107 if (abs(cptr->serv->timestamp - recv_time) > 30)
2109 sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2110 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2111 " this.", timestamp - recv_time);
2112 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2113 me.name, TStime(), me.name);