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
94 #include "ircd_reply.h"
95 #include "ircd_string.h"
101 #include "numnicks.h"
102 #include "querycmds.h"
109 #include "userload.h"
116 * mr_server - registration message handler
118 * parv[0] = sender prefix
119 * parv[1] = servername
121 * parv[3] = start timestamp
122 * parv[4] = link timestamp
123 * parv[5] = major protocol version: P09/P10
124 * parv[parc-1] = serverinfo
126 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
127 * numeric nick mask of this server.
128 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
130 int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
134 char info[REALLEN + 1];
136 struct Client* acptr;
137 struct Client* bcptr;
138 struct Client* LHcptr = 0;
139 struct ConfItem* aconf = 0;
140 struct ConfItem* lhconf = 0;
141 struct Jupe* ajupe = 0;
144 int active_lh_line = 0;
146 time_t start_timestamp;
147 time_t timestamp = 0;
151 if (IsUserPort(cptr))
152 return exit_client_msg(cptr, cptr, &me,
153 "Cannot connect a server to a user port");
155 recv_time = TStime();
160 need_more_params(sptr, "SERVER");
161 return exit_client(cptr, cptr, &me, "Need more parameters");
165 if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
166 return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
168 ircd_log(L_NOTICE, "SERVER: %s %s[%s]", parv[1], cptr->sockhost, cptr->sock_ip);
173 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
174 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
176 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
179 prot = atoi(parv[5] + 1);
180 if (prot > atoi(MAJOR_PROTOCOL))
181 prot = atoi(MAJOR_PROTOCOL);
183 * Because the previous test is only in 2.10, the following is needed
184 * till all servers are 2.10:
186 if (IsServer(cptr) && prot > Protocol(cptr))
187 prot = Protocol(cptr);
189 start_timestamp = atoi(parv[3]);
190 timestamp = atoi(parv[4]);
191 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
192 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
194 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
196 return exit_client_msg(cptr, sptr, &me,
197 "Bogus timestamps (%s %s)", parv[3], parv[4]);
199 ircd_strncpy(info, parv[parc - 1], REALLEN);
200 info[REALLEN] = '\0';
201 if (prot < atoi(MINOR_PROTOCOL)) {
202 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
203 "(%s) from %s", parv[5], cptr->name);
204 return exit_new_server(cptr, sptr, host, timestamp,
205 "Incompatible protocol: %s", parv[5]);
208 * Check for "FRENCH " infection ;-) (actually this should
209 * be replaced with routine to check the hostname syntax in
210 * general). [ This check is still needed, even after the parse
211 * is fixed, because someone can send "SERVER :foo bar " ].
212 * Also, changed to check other "difficult" characters, now
213 * that parse lets all through... --msa
215 if (strlen(host) > HOSTLEN)
216 host[HOSTLEN] = '\0';
218 for (ch = host; *ch; ch++) {
219 if (*ch <= ' ' || *ch > '~')
222 if (*ch || !strchr(host, '.')) {
223 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
225 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
231 * A local server introduces a new server behind this link.
232 * Check if this is allowed according L:, H: and Q: lines.
235 return exit_client_msg(cptr, cptr, &me,
236 "No server info specified for %s", host);
238 * See if the newly found server is behind a guaranteed
239 * leaf (L-line). If so, close the link.
241 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
242 (!lhconf->port || (hop > lhconf->port)))
245 * L: lines normally come in pairs, here we try to
246 * make sure that the oldest link is squitted, not
250 if (timestamp <= cptr->serv->timestamp)
251 LHcptr = 0; /* Kill incoming server */
253 LHcptr = cptr; /* Squit ourselfs */
255 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
256 (lhconf->port && (hop > lhconf->port)))
258 struct Client *ac3ptr;
260 /* Look for net junction causing this: */
261 LHcptr = 0; /* incoming server */
262 if (*parv[5] != 'J') {
263 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
264 if (IsJunction(ac3ptr)) {
273 if (IsUnknown(cptr) || IsHandshake(cptr))
278 * A local link that is still in undefined state wants
279 * to be a SERVER. Check if this is allowed and change
280 * status accordingly...
283 * If there is more then one server on the same machine
284 * that we try to connect to, it could be that the /CONNECT
285 * <mask> caused this connect to be put at the wrong place
286 * in the hashtable. --Run
287 * Same thing for Unknown connections that first send NICK.
289 * Better check if the two strings are (caseless) identical
290 * and not mess with hash internals.
293 if (!EmptyString(cptr->name) &&
294 (IsUnknown(cptr) || IsHandshake(cptr)) &&
295 0 != ircd_strcmp(cptr->name, host))
296 hChangeClient(cptr, host);
297 ircd_strncpy(cptr->name, host, HOSTLEN);
298 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
299 cptr->hopcount = hop;
301 /* check connection rules */
302 if (0 != conf_eval_crule(host, CRULE_ALL)) {
303 ServerStats->is_ref++;
304 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cptr->name);
305 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
308 if (conf_check_server(cptr)) {
309 ++ServerStats->is_ref;
310 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
311 "from %s.", cptr->name);
312 return exit_client(cptr, cptr, &me, "No C:line");
319 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
320 ++ServerStats->is_ref;
322 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
323 "server %s", cptr->name);
324 return exit_client_msg(cptr, cptr, &me,
325 "Access denied. No conf line for server %s", cptr->name);
327 sendto_opmask_butone(0, SNO_OLDSNO, "General C: line active: No line "
328 "for server %s", cptr->name);
329 aconf = find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
331 sendto_opmask_butone(0, SNO_OLDSNO, "Neither C lines for server %s "
332 "nor \"general.undernet.org\"", cptr->name);
333 return exit_client_msg(cptr, cptr, &me, "No C lines for server %s", cptr->name);
337 #ifdef CRYPT_LINK_PASSWORD
338 /* passwd may be NULL. Head it off at the pass... */
340 encr = ircd_crypt(cptr->passwd, aconf->passed);
346 #endif /* CRYPT_LINK_PASSWORD */
348 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
349 ++ServerStats->is_ref;
350 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
352 return exit_client_msg(cptr, cptr, &me,
353 "No Access (passwd mismatch) %s", cptr->name);
355 #endif /* not GODMODE */
356 memset(cptr->passwd, 0, sizeof(cptr->passwd));
359 for (i = 0; i <= HighestFd; i++)
360 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
369 * We want to find IsConnecting() and IsHandshake() too,
371 * The second finds collisions with numeric representation of existing
372 * servers - these shouldn't happen anymore when all upgraded to 2.10.
375 while ((acptr = FindClient(host)) ||
376 (parc > 7 && (acptr = FindNServer(parv[6]))))
379 * This link is trying feed me a server that I already have
380 * access through another path
382 * Do not allow Uworld to do this.
383 * Do not allow servers that are juped.
384 * Do not allow servers that have older link timestamps
386 * Do not allow servers that use the same numeric as an existing
387 * server, but have a different name.
389 * If my ircd.conf sucks, I can try to connect to myself:
392 return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
394 * Detect wrong numeric.
396 if (0 != ircd_strcmp(acptr->name, host)) {
397 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
398 ":SERVER Numeric Collision: %s != %s",
400 return exit_client_msg(cptr, cptr, &me,
401 "NUMERIC collision between %s and %s."
402 " Is your server numeric correct ?", host, acptr->name);
405 * Kill our try, if we had one.
407 if (IsConnecting(acptr))
409 if (!active_lh_line && exit_client(cptr, acptr, &me,
410 "Just connected via another link") == CPTR_KILLED)
413 * We can have only ONE 'IsConnecting', 'IsHandshake' or
414 * 'IsServer', because new 'IsConnecting's are refused to
415 * the same server if we already had it.
420 * Avoid other nick collisions...
421 * This is a doubtfull test though, what else would it be
422 * when it has a server.name ?
424 else if (!IsServer(acptr) && !IsHandshake(acptr))
425 return exit_client_msg(cptr, cptr, &me,
426 "Nickname %s already exists!", host);
428 * Our new server might be a juped server,
429 * or someone trying abuse a second Uworld:
431 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
432 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
435 return exit_client(cptr, sptr, &me, acptr->info);
436 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
437 ":Received :%s SERVER %s from %s !?!", parv[0],
438 parv[1], cptr->name);
439 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
442 * Of course we find the handshake this link was before :)
444 else if (IsHandshake(acptr) && acptr == cptr)
447 * Here we have a server nick collision...
448 * We don't want to kill the link that was last /connected,
449 * but we neither want to kill a good (old) link.
450 * Therefor we kill the second youngest link.
454 struct Client* c2ptr = 0;
455 struct Client* c3ptr = acptr;
456 struct Client* ac2ptr;
457 struct Client* ac3ptr;
459 /* Search youngest link: */
460 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
461 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
465 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
466 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
469 if (timestamp > c3ptr->serv->timestamp)
472 c2ptr = acptr; /* Make sure they differ */
474 /* Search second youngest link: */
475 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
476 if (ac2ptr != c3ptr &&
477 ac2ptr->serv->timestamp >
478 (c2ptr ? c2ptr->serv->timestamp : timestamp))
482 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
483 if (ac2ptr != c3ptr &&
484 ac2ptr->serv->timestamp >
485 (c2ptr ? c2ptr->serv->timestamp : timestamp))
488 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
490 /* If timestamps are equal, decide which link to break
493 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
494 (c3ptr ? c3ptr->serv->timestamp : timestamp))
503 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
508 n2up = IsServer(sptr) ? sptr->name : me.name;
513 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
518 n3up = IsServer(sptr) ? sptr->name : me.name;
520 if (strcmp(n2, n2up) > 0)
522 if (strcmp(n3, n3up) > 0)
524 if (strcmp(n3, n2) > 0)
531 /* Now squit the second youngest link: */
533 return exit_new_server(cptr, sptr, host, timestamp,
534 "server %s already exists and is %ld seconds younger.",
535 host, (long)acptr->serv->timestamp - (long)timestamp);
536 else if (c2ptr->from == cptr || IsServer(sptr))
538 struct Client *killedptrfrom = c2ptr->from;
542 * If the L: or H: line also gets rid of this link,
543 * we sent just one squit.
545 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
548 * If breaking the loop here solves the L: or H:
549 * line problem, we don't squit that.
551 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
556 * If we still have a L: or H: line problem,
557 * we prefer to squit the new server, solving
558 * loop and L:/H: line problem with only one squit.
565 * If the new server was introduced by a server that caused a
566 * Ghost less then 20 seconds ago, this is probably also
567 * a Ghost... (20 seconds is more then enough because all
568 * SERVER messages are at the beginning of a net.burst). --Run
570 if (CurrentTime - cptr->serv->ghost < 20)
572 killedptrfrom = acptr->from;
573 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
576 else if (exit_client_msg(cptr, c2ptr, &me,
577 "Loop <-- %s (new link is %ld seconds younger)", host,
578 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
579 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
582 * Did we kill the incoming server off already ?
584 if (killedptrfrom == cptr)
591 if (LHcptr && a_kills_b_too(LHcptr, acptr))
593 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
602 * We can't believe it is a lagged server message
603 * when it directly connects to us...
604 * kill the older link at the ghost, rather then
605 * at the second youngest link, assuming it isn't
608 ghost = CurrentTime; /* Mark that it caused a ghost */
609 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
619 return exit_new_server(cptr, sptr, host, timestamp,
620 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
621 "Leaf-only link %s <- %s(%s), check L:",
623 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
627 int killed = a_kills_b_too(LHcptr, sptr);
628 if (active_lh_line < 3)
630 if (exit_client_msg(cptr, LHcptr, &me,
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 : "*") : "!") == CPTR_KILLED)
639 ServerStats->is_ref++;
640 if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
644 * Did we kill the incoming server off already ?
654 * Server is informing about a new server behind
655 * this link. Create REMOTE server structure,
656 * add it to list and propagate word to my other
660 acptr = make_client(cptr, STAT_SERVER);
662 acptr->serv->prot = prot;
663 acptr->serv->timestamp = timestamp;
664 acptr->hopcount = hop;
665 ircd_strncpy(acptr->name, host, HOSTLEN);
666 ircd_strncpy(acptr->info, info, REALLEN);
667 acptr->serv->up = sptr;
668 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
669 /* Use cptr, because we do protocol 9 -> 10 translation
670 for numeric nicks ! */
671 SetServerYXX(cptr, acptr, parv[6]);
673 Count_newremoteserver(UserStats);
674 if (Protocol(acptr) < 10)
675 acptr->flags |= FLAGS_TS8;
676 add_client_to_list(acptr);
681 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
682 sptr->name, acptr->name);
686 * Old sendto_serv_but_one() call removed because we now need to send
687 * different names to different servers (domain name matching).
689 * Personally, I think this is bogus; it's a feature we don't use here.
692 for (i = 0; i <= HighestFd; i++)
694 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
695 bcptr == cptr || IsMe(bcptr))
697 if (0 == match(me.name, acptr->name))
699 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
700 acptr->name, hop + 1, parv[4], parv[5], NumServCap(acptr),
706 if (IsUnknown(cptr) || IsHandshake(cptr))
709 cptr->serv->timestamp = timestamp;
710 cptr->serv->prot = prot;
711 cptr->serv->ghost = ghost;
712 SetServerYXX(cptr, cptr, parv[6]);
713 if (start_timestamp > OLDEST_TS)
715 #ifndef RELIABLE_CLOCK
717 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
718 "others start time: %Tu", me.serv->timestamp,
720 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
721 "received timestamp: %Tu ; difference %ld",
722 recv_time, timestamp, timestamp - recv_time);
724 if (start_timestamp < me.serv->timestamp)
726 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
727 "%Tu < %Tu", start_timestamp, me.serv->timestamp);
728 me.serv->timestamp = start_timestamp;
729 TSoffset += timestamp - recv_time;
730 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
731 (int)(timestamp - recv_time));
733 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
734 cptr->serv->timestamp = TStime();
736 else if (timestamp != recv_time)
739 * Equal start times, we have a collision. Let the connected-to server
740 * decide. This assumes leafs issue more than half of the connection
744 cptr->serv->timestamp = TStime();
745 else if (IsHandshake(cptr))
747 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
748 (int)(timestamp - recv_time));
749 TSoffset += timestamp - recv_time;
752 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
753 if (start_timestamp < me.serv->timestamp)
754 me.serv->timestamp = start_timestamp;
756 cptr->serv->timestamp = TStime();
760 ret = server_estab(cptr, aconf, ajupe);
764 #ifdef RELIABLE_CLOCK
765 if (abs(cptr->serv->timestamp - recv_time) > 30)
767 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
768 "timestamp-clock difference of %Td seconds! "
769 "Used SETTIME to correct this.",
770 timestamp - recv_time);
771 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), me.name);
779 * ms_server - server message handler
781 * parv[0] = sender prefix
782 * parv[1] = servername
784 * parv[3] = start timestamp
785 * parv[4] = link timestamp
786 * parv[5] = major protocol version: P09/P10
787 * parv[parc-1] = serverinfo
789 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
790 * numeric nick mask of this server.
791 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
792 * parv[8] = %<lastmod> - optional parameter only present if there's an
793 * outstanding JUPE; specifies the JUPE's lastmod field
795 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
799 char info[REALLEN + 1];
801 struct Client* acptr;
802 struct Client* bcptr;
803 struct Client* LHcptr = 0;
804 struct ConfItem* aconf = 0;
805 struct ConfItem* lhconf = 0;
806 struct Jupe* ajupe = 0;
809 int active_lh_line = 0;
811 time_t start_timestamp;
812 time_t timestamp = 0;
817 if (IsUserPort(cptr))
818 return exit_client_msg(cptr, cptr, &me,
819 "Cannot connect a server to a user port");
821 recv_time = TStime();
825 return need_more_params(sptr, "SERVER");
826 return exit_client(cptr, cptr, &me, "Need more parameters");
833 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
834 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
836 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
839 prot = atoi(parv[5] + 1);
840 if (prot > atoi(MAJOR_PROTOCOL))
841 prot = atoi(MAJOR_PROTOCOL);
843 * Because the previous test is only in 2.10, the following is needed
844 * till all servers are 2.10:
846 if (IsServer(cptr) && prot > Protocol(cptr))
847 prot = Protocol(cptr);
849 start_timestamp = atoi(parv[3]);
850 timestamp = atoi(parv[4]);
851 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
852 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
853 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
855 return exit_client_msg(cptr, sptr, &me,
856 "Bogus timestamps (%s %s)", parv[3], parv[4]);
858 ircd_strncpy(info, parv[parc - 1], REALLEN);
859 info[REALLEN] = '\0';
860 if (prot < atoi(MINOR_PROTOCOL)) {
861 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
862 "(%s) from %s", parv[5], cptr->name);
863 return exit_new_server(cptr, sptr, host, timestamp,
864 "Incompatible protocol: %s", parv[5]);
866 if (parc > 9 && *parv[8] == '%')
867 lastmod = atoi(parv[8] + 1);
868 /* If there's a jupe that matches, and it's a global jupe, and the
869 * introducer didn't indicate it knew of the jupe or has an older
870 * version of the jupe, and the connection isn't in a BURST, resynch
873 if ((ajupe = jupe_find(host)) && !JupeIsLocal(ajupe) &&
874 JupeLastMod(ajupe) > lastmod && !IsBurstOrBurstAck(cptr))
875 jupe_resend(cptr, ajupe);
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_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
892 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
898 * A local server introduces a new server behind this link.
899 * Check if this is allowed according L:, H: and Q: lines.
902 return exit_client_msg(cptr, cptr, &me,
903 "No server info specified for %s", host);
905 * See if the newly found server is behind a guaranteed
906 * leaf (L-line). If so, close the link.
908 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
909 (!lhconf->port || (hop > lhconf->port)))
912 * L: lines normally come in pairs, here we try to
913 * make sure that the oldest link is squitted, not
917 if (timestamp <= cptr->serv->timestamp)
918 LHcptr = 0; /* Kill incoming server */
920 LHcptr = cptr; /* Squit ourselfs */
922 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
923 (lhconf->port && (hop > lhconf->port)))
925 struct Client *ac3ptr;
927 /* Look for net junction causing this: */
928 LHcptr = 0; /* incoming server */
929 if (*parv[5] != 'J') {
930 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
931 if (IsJunction(ac3ptr)) {
940 if (IsUnknown(cptr) || IsHandshake(cptr))
945 * A local link that is still in undefined state wants
946 * to be a SERVER. Check if this is allowed and change
947 * status accordingly...
950 * If there is more then one server on the same machine
951 * that we try to connect to, it could be that the /CONNECT
952 * <mask> caused this connect to be put at the wrong place
953 * in the hashtable. --Run
954 * Same thing for Unknown connections that first send NICK.
956 * Better check if the two strings are (caseless) identical
957 * and not mess with hash internals.
960 if ((!(EmptyString(cptr->name)))
961 && (IsUnknown(cptr) || IsHandshake(cptr))
962 && 0 != ircd_strcmp(cptr->name, host))
963 hChangeClient(cptr, host);
964 ircd_strncpy(cptr->name, host, HOSTLEN);
965 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
966 cptr->hopcount = hop;
968 /* check connection rules */
969 if (0 != conf_eval_crule(host, CRULE_ALL)) {
970 ServerStats->is_ref++;
971 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cptr->name);
972 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
974 if (conf_check_server(cptr)) {
975 ++ServerStats->is_ref;
976 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
977 "from %s.", cptr->name);
978 return exit_client(cptr, cptr, &me, "No C conf lines");
985 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
986 ++ServerStats->is_ref;
988 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
989 "server %s", cptr->name);
990 return exit_client_msg(cptr, cptr, &me,
991 "Access denied. No conf line for server %s", cptr->name);
993 sendto_opmask_butone(0, SNO_OLDSNO, "General C line active: No line "
994 "for server %s", cptr->name);
996 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
998 sendto_opmask_butone(0, SNO_OLDSNO, "Neither C lines for server %s "
999 "nor \"general.undernet.org\"", cptr->name);
1000 return exit_client_msg(cptr, cptr, &me,
1001 "No C lines for server %s", cptr->name);
1003 #endif /* GODMODE */
1005 #ifdef CRYPT_LINK_PASSWORD
1006 /* passwd may be NULL. Head it off at the pass... */
1009 encr = ircd_crypt(cptr->passwd, aconf->passwd);
1014 encr = cptr->passwd;
1015 #endif /* CRYPT_LINK_PASSWORD */
1017 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1018 ++ServerStats->is_ref;
1019 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
1021 return exit_client_msg(cptr, cptr, &me,
1022 "No Access (passwd mismatch) %s", cptr->name);
1024 #endif /* not GODMODE */
1025 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1028 for (i = 0; i <= HighestFd; i++)
1029 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1038 * We want to find IsConnecting() and IsHandshake() too,
1040 * The second finds collisions with numeric representation of existing
1041 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1044 while ((acptr = FindClient(host)) ||
1045 (parc > 7 && (acptr = FindNServer(parv[6]))))
1048 * This link is trying feed me a server that I already have
1049 * access through another path
1051 * Do not allow Uworld to do this.
1052 * Do not allow servers that are juped.
1053 * Do not allow servers that have older link timestamps
1055 * Do not allow servers that use the same numeric as an existing
1056 * server, but have a different name.
1058 * If my ircd.conf sucks, I can try to connect to myself:
1061 return exit_client_msg(cptr, cptr, &me,
1062 "nick collision with me, check server number in M:? (%s)", host);
1064 * Detect wrong numeric.
1066 if (0 != ircd_strcmp(acptr->name, host))
1068 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1069 ":SERVER Numeric Collision: %s != %s", acptr->name,
1071 return exit_client_msg(cptr, cptr, &me,
1072 "NUMERIC collision between %s and %s."
1073 " Is your server numeric correct ?", host, acptr->name);
1076 * Kill our try, if we had one.
1078 if (IsConnecting(acptr))
1080 if (!active_lh_line && exit_client(cptr, acptr, &me,
1081 "Just connected via another link") == CPTR_KILLED)
1084 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1085 * 'IsServer', because new 'IsConnecting's are refused to
1086 * the same server if we already had it.
1091 * Avoid other nick collisions...
1092 * This is a doubtfull test though, what else would it be
1093 * when it has a server.name ?
1095 else if (!IsServer(acptr) && !IsHandshake(acptr))
1096 return exit_client_msg(cptr, cptr, &me,
1097 "Nickname %s already exists!", host);
1099 * Our new server might be a juped server,
1100 * or someone trying abuse a second Uworld:
1102 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1103 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1105 if (!IsServer(sptr))
1106 return exit_client(cptr, sptr, &me, acptr->info);
1107 sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1108 "from %s !?!", parv[0], parv[1], cptr->name);
1109 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1112 * Of course we find the handshake this link was before :)
1114 else if (IsHandshake(acptr) && acptr == cptr)
1117 * Here we have a server nick collision...
1118 * We don't want to kill the link that was last /connected,
1119 * but we neither want to kill a good (old) link.
1120 * Therefor we kill the second youngest link.
1124 struct Client* c2ptr = 0;
1125 struct Client* c3ptr = acptr;
1126 struct Client* ac2ptr;
1127 struct Client* ac3ptr;
1129 /* Search youngest link: */
1130 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1131 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1135 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1136 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1139 if (timestamp > c3ptr->serv->timestamp)
1142 c2ptr = acptr; /* Make sure they differ */
1144 /* Search second youngest link: */
1145 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1146 if (ac2ptr != c3ptr &&
1147 ac2ptr->serv->timestamp >
1148 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1152 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1153 if (ac2ptr != c3ptr &&
1154 ac2ptr->serv->timestamp >
1155 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1158 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1160 /* If timestamps are equal, decide which link to break
1163 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1164 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1173 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1178 n2up = IsServer(sptr) ? sptr->name : me.name;
1183 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1188 n3up = IsServer(sptr) ? sptr->name : me.name;
1190 if (strcmp(n2, n2up) > 0)
1192 if (strcmp(n3, n3up) > 0)
1194 if (strcmp(n3, n2) > 0)
1201 /* Now squit the second youngest link: */
1203 return exit_new_server(cptr, sptr, host, timestamp,
1204 "server %s already exists and is %ld seconds younger.",
1205 host, (long)acptr->serv->timestamp - (long)timestamp);
1206 else if (c2ptr->from == cptr || IsServer(sptr))
1208 struct Client *killedptrfrom = c2ptr->from;
1212 * If the L: or H: line also gets rid of this link,
1213 * we sent just one squit.
1215 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1218 * If breaking the loop here solves the L: or H:
1219 * line problem, we don't squit that.
1221 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1226 * If we still have a L: or H: line problem,
1227 * we prefer to squit the new server, solving
1228 * loop and L:/H: line problem with only one squit.
1235 * If the new server was introduced by a server that caused a
1236 * Ghost less then 20 seconds ago, this is probably also
1237 * a Ghost... (20 seconds is more then enough because all
1238 * SERVER messages are at the beginning of a net.burst). --Run
1240 if (CurrentTime - cptr->serv->ghost < 20)
1242 killedptrfrom = acptr->from;
1243 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1246 else if (exit_client_msg(cptr, c2ptr, &me,
1247 "Loop <-- %s (new link is %ld seconds younger)", host,
1248 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1249 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1252 * Did we kill the incoming server off already ?
1254 if (killedptrfrom == cptr)
1261 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1263 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1272 * We can't believe it is a lagged server message
1273 * when it directly connects to us...
1274 * kill the older link at the ghost, rather then
1275 * at the second youngest link, assuming it isn't
1278 ghost = CurrentTime; /* Mark that it caused a ghost */
1279 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1289 return exit_new_server(cptr, sptr, host, timestamp,
1290 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1292 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1296 int killed = a_kills_b_too(LHcptr, sptr);
1297 if (active_lh_line < 3)
1299 if (exit_client_msg(cptr, LHcptr, &me,
1300 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1302 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1307 ServerStats->is_ref++;
1308 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1312 * Did we kill the incoming server off already ?
1322 * Server is informing about a new server behind
1323 * this link. Create REMOTE server structure,
1324 * add it to list and propagate word to my other
1328 acptr = make_client(cptr, STAT_SERVER);
1330 acptr->serv->prot = prot;
1331 acptr->serv->timestamp = timestamp;
1332 acptr->hopcount = hop;
1333 ircd_strncpy(acptr->name, host, HOSTLEN);
1334 ircd_strncpy(acptr->info, info, REALLEN);
1335 acptr->serv->up = sptr;
1336 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1337 /* Use cptr, because we do protocol 9 -> 10 translation
1338 for numeric nicks ! */
1339 SetServerYXX(cptr, acptr, parv[6]);
1341 Count_newremoteserver(UserStats);
1342 if (Protocol(acptr) < 10)
1343 acptr->flags |= FLAGS_TS8;
1344 add_client_to_list(acptr);
1346 if (*parv[5] == 'J')
1349 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1350 sptr->name, acptr->name);
1354 * Old sendto_serv_but_one() call removed because we now need to send
1355 * different names to different servers (domain name matching).
1357 for (i = 0; i <= HighestFd; i++)
1359 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1360 bcptr == cptr || IsMe(bcptr))
1362 if (0 == match(me.name, acptr->name))
1364 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1365 acptr->name, hop + 1, parv[4], parv[5], NumServCap(acptr),
1371 if (IsUnknown(cptr) || IsHandshake(cptr))
1374 cptr->serv->timestamp = timestamp;
1375 cptr->serv->prot = prot;
1376 cptr->serv->ghost = ghost;
1377 SetServerYXX(cptr, cptr, parv[6]);
1378 if (start_timestamp > OLDEST_TS)
1380 #ifndef RELIABLE_CLOCK
1382 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
1383 "others start time: %Tu", me.serv->timestamp,
1385 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
1386 "received timestamp: %Tu ; difference %ld",
1387 recv_time, timestamp, timestamp - recv_time);
1389 if (start_timestamp < me.serv->timestamp)
1391 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1392 "%Tu < %Tu", start_timestamp, me.serv->timestamp);
1393 me.serv->timestamp = start_timestamp;
1394 TSoffset += timestamp - recv_time;
1395 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1396 (int)(timestamp - recv_time));
1398 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1399 cptr->serv->timestamp = TStime();
1401 else if (timestamp != recv_time)
1404 * Equal start times, we have a collision. Let the connected-to server
1405 * decide. This assumes leafs issue more than half of the connection
1408 if (IsUnknown(cptr))
1409 cptr->serv->timestamp = TStime();
1410 else if (IsHandshake(cptr))
1412 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1413 (int)(timestamp - recv_time));
1414 TSoffset += timestamp - recv_time;
1417 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
1418 if (start_timestamp < me.serv->timestamp)
1419 me.serv->timestamp = start_timestamp;
1420 if (IsUnknown(cptr))
1421 cptr->serv->timestamp = TStime();
1425 ret = server_estab(cptr, aconf, ajupe);
1429 #ifdef RELIABLE_CLOCK
1430 if (abs(cptr->serv->timestamp - recv_time) > 30)
1432 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1433 "timestamp-clock difference of %Td seconds! Used "
1434 "SETTIME to correct this.", timestamp - recv_time);
1435 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), me.name);
1447 * parv[0] = sender prefix
1448 * parv[1] = servername
1449 * parv[2] = hopcount
1450 * parv[3] = start timestamp
1451 * parv[4] = link timestamp
1452 * parv[5] = major protocol version: P09/P10
1453 * parv[parc-1] = serverinfo
1455 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1456 * numeric nick mask of this server.
1457 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1459 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1463 char info[REALLEN + 1];
1465 struct Client* acptr;
1466 struct Client* bcptr;
1467 struct Client* LHcptr = 0;
1468 struct ConfItem* aconf = 0;
1469 struct ConfItem* lhconf = 0;
1470 struct Jupe* ajupe = 0;
1473 int active_lh_line = 0;
1474 unsigned short prot;
1475 time_t start_timestamp;
1476 time_t timestamp = 0;
1482 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1486 if (IsUserPort(cptr))
1487 return exit_client_msg(cptr, cptr, &me,
1488 "You cannot connect a server to a user port; connect to %s port %u",
1489 me.name, server_port);
1491 recv_time = TStime();
1495 return need_more_params(sptr, "SERVER");
1496 return exit_client(cptr, cptr, &me, "Need more parameters");
1502 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1503 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1505 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1508 prot = atoi(parv[5] + 1);
1509 if (prot > atoi(MAJOR_PROTOCOL))
1510 prot = atoi(MAJOR_PROTOCOL);
1512 * Because the previous test is only in 2.10, the following is needed
1513 * till all servers are 2.10:
1515 if (IsServer(cptr) && prot > Protocol(cptr))
1516 prot = Protocol(cptr);
1517 hop = atoi(parv[2]);
1518 start_timestamp = atoi(parv[3]);
1519 timestamp = atoi(parv[4]);
1520 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1521 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1522 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1524 return exit_client_msg(cptr, sptr, &me,
1525 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1527 ircd_strncpy(info, parv[parc - 1], REALLEN);
1528 info[REALLEN] = '\0';
1529 if (prot < atoi(MINOR_PROTOCOL)) {
1530 sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1531 parv[5], cptr->name);
1532 return exit_new_server(cptr, sptr, host, timestamp,
1533 "Incompatible protocol: %s", parv[5]);
1536 * Check for "FRENCH " infection ;-) (actually this should
1537 * be replaced with routine to check the hostname syntax in
1538 * general). [ This check is still needed, even after the parse
1539 * is fixed, because someone can send "SERVER :foo bar " ].
1540 * Also, changed to check other "difficult" characters, now
1541 * that parse lets all through... --msa
1543 if (strlen(host) > HOSTLEN)
1544 host[HOSTLEN] = '\0';
1545 for (ch = host; *ch; ch++)
1546 if (*ch <= ' ' || *ch > '~')
1548 if (*ch || !strchr(host, '.'))
1550 sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1551 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1557 * A local server introduces a new server behind this link.
1558 * Check if this is allowed according L:, H: and Q: lines.
1560 if (info[0] == '\0')
1561 return exit_client_msg(cptr, cptr, &me,
1562 "No server info specified for %s", host);
1564 * See if the newly found server is behind a guaranteed
1565 * leaf (L-line). If so, close the link.
1567 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1568 (!lhconf->port || (hop > lhconf->port)))
1571 * L: lines normally come in pairs, here we try to
1572 * make sure that the oldest link is squitted, not
1576 if (timestamp <= cptr->serv->timestamp)
1577 LHcptr = 0; /* Kill incoming server */
1579 LHcptr = cptr; /* Squit ourselfs */
1581 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1582 (lhconf->port && (hop > lhconf->port)))
1584 struct Client *ac3ptr;
1586 /* Look for net junction causing this: */
1587 LHcptr = 0; /* incoming server */
1588 if (*parv[5] != 'J') {
1589 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1590 if (IsJunction(ac3ptr)) {
1599 if (IsUnknown(cptr) || IsHandshake(cptr))
1604 * A local link that is still in undefined state wants
1605 * to be a SERVER. Check if this is allowed and change
1606 * status accordingly...
1609 * If there is more then one server on the same machine
1610 * that we try to connect to, it could be that the /CONNECT
1611 * <mask> caused this connect to be put at the wrong place
1612 * in the hashtable. --Run
1613 * Same thing for Unknown connections that first send NICK.
1615 * Better check if the two strings are (caseless) identical
1616 * and not mess with hash internals.
1619 if ((!(EmptyString(cptr->name)))
1620 && (IsUnknown(cptr) || IsHandshake(cptr))
1621 && 0 != ircd_strcmp(cptr->name, host))
1622 hChangeClient(cptr, host);
1623 ircd_strncpy(cptr->name, host, HOSTLEN);
1624 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1625 cptr->hopcount = hop;
1627 /* check connection rules */
1628 if (0 != conf_eval_crule(host, CRULE_ALL)) {
1629 ServerStats->is_ref++;
1630 sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1631 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1633 if (conf_check_server(cptr)) {
1634 ++ServerStats->is_ref;
1635 sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1636 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1643 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1644 ++ServerStats->is_ref;
1646 sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1647 return exit_client_msg(cptr, cptr, &me,
1648 "Access denied. No conf line for server %s", cptr->name);
1650 sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1652 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1654 sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1655 "\"general.undernet.org\"", cptr->name);
1656 return exit_client_msg(cptr, cptr, &me,
1657 "No C/N lines for server %s", cptr->name);
1659 #endif /* GODMODE */
1661 #ifdef CRYPT_LINK_PASSWORD
1662 /* passwd may be NULL. Head it off at the pass... */
1665 encr = ircd_crypt(cptr->passwd, aconf->passwd);
1670 encr = cptr->passwd;
1671 #endif /* CRYPT_LINK_PASSWORD */
1673 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1674 ++ServerStats->is_ref;
1675 sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1676 return exit_client_msg(cptr, cptr, &me,
1677 "No Access (passwd mismatch) %s", cptr->name);
1679 #endif /* not GODMODE */
1680 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1683 for (i = 0; i <= HighestFd; i++)
1684 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1693 * We want to find IsConnecting() and IsHandshake() too,
1695 * The second finds collisions with numeric representation of existing
1696 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1699 while ((acptr = FindClient(host)) ||
1700 (parc > 7 && (acptr = FindNServer(parv[6]))))
1703 * This link is trying feed me a server that I already have
1704 * access through another path
1706 * Do not allow Uworld to do this.
1707 * Do not allow servers that are juped.
1708 * Do not allow servers that have older link timestamps
1710 * Do not allow servers that use the same numeric as an existing
1711 * server, but have a different name.
1713 * If my ircd.conf sucks, I can try to connect to myself:
1716 return exit_client_msg(cptr, cptr, &me,
1717 "nick collision with me, check server number in M:? (%s)", host);
1719 * Detect wrong numeric.
1721 if (0 != ircd_strcmp(acptr->name, host))
1723 sendto_serv_butone(cptr, /* XXX DEAD */
1724 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1725 me.name, acptr->name, host);
1726 return exit_client_msg(cptr, cptr, &me,
1727 "NUMERIC collision between %s and %s."
1728 " Is your server numeric correct ?", host, acptr->name);
1731 * Kill our try, if we had one.
1733 if (IsConnecting(acptr))
1735 if (!active_lh_line && exit_client(cptr, acptr, &me,
1736 "Just connected via another link") == CPTR_KILLED)
1739 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1740 * 'IsServer', because new 'IsConnecting's are refused to
1741 * the same server if we already had it.
1746 * Avoid other nick collisions...
1747 * This is a doubtfull test though, what else would it be
1748 * when it has a server.name ?
1750 else if (!IsServer(acptr) && !IsHandshake(acptr))
1751 return exit_client_msg(cptr, cptr, &me,
1752 "Nickname %s already exists!", host);
1754 * Our new server might be a juped server,
1755 * or someone trying abuse a second Uworld:
1757 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1758 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1760 if (!IsServer(sptr))
1761 return exit_client(cptr, sptr, &me, acptr->info);
1762 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1763 me.name, parv[0], parv[1], cptr->name);
1764 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1767 * Of course we find the handshake this link was before :)
1769 else if (IsHandshake(acptr) && acptr == cptr)
1772 * Here we have a server nick collision...
1773 * We don't want to kill the link that was last /connected,
1774 * but we neither want to kill a good (old) link.
1775 * Therefor we kill the second youngest link.
1779 struct Client* c2ptr = 0;
1780 struct Client* c3ptr = acptr;
1781 struct Client* ac2ptr;
1782 struct Client* ac3ptr;
1784 /* Search youngest link: */
1785 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1786 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1790 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1791 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1794 if (timestamp > c3ptr->serv->timestamp)
1797 c2ptr = acptr; /* Make sure they differ */
1799 /* Search second youngest link: */
1800 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1801 if (ac2ptr != c3ptr &&
1802 ac2ptr->serv->timestamp >
1803 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1807 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1808 if (ac2ptr != c3ptr &&
1809 ac2ptr->serv->timestamp >
1810 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1813 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1815 /* If timestamps are equal, decide which link to break
1818 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1819 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1828 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1833 n2up = IsServer(sptr) ? sptr->name : me.name;
1838 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1843 n3up = IsServer(sptr) ? sptr->name : me.name;
1845 if (strcmp(n2, n2up) > 0)
1847 if (strcmp(n3, n3up) > 0)
1849 if (strcmp(n3, n2) > 0)
1856 /* Now squit the second youngest link: */
1858 return exit_new_server(cptr, sptr, host, timestamp,
1859 "server %s already exists and is %ld seconds younger.",
1860 host, (long)acptr->serv->timestamp - (long)timestamp);
1861 else if (c2ptr->from == cptr || IsServer(sptr))
1863 struct Client *killedptrfrom = c2ptr->from;
1867 * If the L: or H: line also gets rid of this link,
1868 * we sent just one squit.
1870 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1873 * If breaking the loop here solves the L: or H:
1874 * line problem, we don't squit that.
1876 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1881 * If we still have a L: or H: line problem,
1882 * we prefer to squit the new server, solving
1883 * loop and L:/H: line problem with only one squit.
1890 * If the new server was introduced by a server that caused a
1891 * Ghost less then 20 seconds ago, this is probably also
1892 * a Ghost... (20 seconds is more then enough because all
1893 * SERVER messages are at the beginning of a net.burst). --Run
1895 if (CurrentTime - cptr->serv->ghost < 20)
1897 killedptrfrom = acptr->from;
1898 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1901 else if (exit_client_msg(cptr, c2ptr, &me,
1902 "Loop <-- %s (new link is %ld seconds younger)", host,
1903 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1904 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1907 * Did we kill the incoming server off already ?
1909 if (killedptrfrom == cptr)
1916 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1918 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1927 * We can't believe it is a lagged server message
1928 * when it directly connects to us...
1929 * kill the older link at the ghost, rather then
1930 * at the second youngest link, assuming it isn't
1933 ghost = CurrentTime; /* Mark that it caused a ghost */
1934 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1944 return exit_new_server(cptr, sptr, host, timestamp,
1945 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1947 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1951 int killed = a_kills_b_too(LHcptr, sptr);
1952 if (active_lh_line < 3)
1954 if (exit_client_msg(cptr, LHcptr, &me,
1955 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1957 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1962 ServerStats->is_ref++;
1963 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1967 * Did we kill the incoming server off already ?
1977 * Server is informing about a new server behind
1978 * this link. Create REMOTE server structure,
1979 * add it to list and propagate word to my other
1983 acptr = make_client(cptr, STAT_SERVER);
1985 acptr->serv->prot = prot;
1986 acptr->serv->timestamp = timestamp;
1987 acptr->hopcount = hop;
1988 ircd_strncpy(acptr->name, host, HOSTLEN);
1989 ircd_strncpy(acptr->info, info, REALLEN);
1990 acptr->serv->up = sptr;
1991 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1992 /* Use cptr, because we do protocol 9 -> 10 translation
1993 for numeric nicks ! */
1994 SetServerYXX(cptr, acptr, parv[6]);
1996 Count_newremoteserver(UserStats);
1997 if (Protocol(acptr) < 10)
1998 acptr->flags |= FLAGS_TS8;
1999 add_client_to_list(acptr);
2001 if (*parv[5] == 'J')
2004 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
2005 sptr->name, acptr->name);
2009 * Old sendto_serv_but_one() call removed because we now need to send
2010 * different names to different servers (domain name matching).
2012 for (i = 0; i <= HighestFd; i++)
2014 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
2015 bcptr == cptr || IsMe(bcptr))
2017 if (0 == match(me.name, acptr->name))
2019 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
2020 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
2021 NumServCap(acptr), acptr->info);
2026 if (IsUnknown(cptr) || IsHandshake(cptr))
2029 cptr->serv->timestamp = timestamp;
2030 cptr->serv->prot = prot;
2031 cptr->serv->ghost = ghost;
2032 SetServerYXX(cptr, cptr, parv[6]);
2033 if (start_timestamp > OLDEST_TS)
2035 #ifndef RELIABLE_CLOCK
2037 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
2038 TIME_T_FMT, me.serv->timestamp, start_timestamp);
2039 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
2040 TIME_T_FMT " ; difference %ld",
2041 recv_time, timestamp, timestamp - recv_time);
2043 if (start_timestamp < me.serv->timestamp)
2045 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
2046 start_timestamp, me.serv->timestamp);
2047 me.serv->timestamp = start_timestamp;
2048 TSoffset += timestamp - recv_time;
2049 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
2051 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
2052 cptr->serv->timestamp = TStime();
2054 else if (timestamp != recv_time)
2057 * Equal start times, we have a collision. Let the connected-to server
2058 * decide. This assumes leafs issue more than half of the connection
2061 if (IsUnknown(cptr))
2062 cptr->serv->timestamp = TStime();
2063 else if (IsHandshake(cptr))
2065 sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
2066 (int)(timestamp - recv_time));
2067 TSoffset += timestamp - recv_time;
2070 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2071 if (start_timestamp < me.serv->timestamp)
2072 me.serv->timestamp = start_timestamp;
2073 if (IsUnknown(cptr))
2074 cptr->serv->timestamp = TStime();
2078 ret = server_estab(cptr, aconf); /* XXX DEAD */
2082 #ifdef RELIABLE_CLOCK
2083 if (abs(cptr->serv->timestamp - recv_time) > 30)
2085 sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2086 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2087 " this.", timestamp - recv_time);
2088 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2089 me.name, TStime(), me.name);