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 log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "SERVER: %s %s[%s]", parv[1],
169 cptr->sockhost, cptr->sock_ip);
174 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
175 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
177 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
180 prot = atoi(parv[5] + 1);
181 if (prot > atoi(MAJOR_PROTOCOL))
182 prot = atoi(MAJOR_PROTOCOL);
184 * Because the previous test is only in 2.10, the following is needed
185 * till all servers are 2.10:
187 if (IsServer(cptr) && prot > Protocol(cptr))
188 prot = Protocol(cptr);
190 start_timestamp = atoi(parv[3]);
191 timestamp = atoi(parv[4]);
192 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
193 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
195 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
197 return exit_client_msg(cptr, sptr, &me,
198 "Bogus timestamps (%s %s)", parv[3], parv[4]);
200 ircd_strncpy(info, parv[parc - 1], REALLEN);
201 info[REALLEN] = '\0';
202 if (prot < atoi(MINOR_PROTOCOL)) {
203 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
204 "(%s) from %s", parv[5], cptr->name);
205 return exit_new_server(cptr, sptr, host, timestamp,
206 "Incompatible protocol: %s", parv[5]);
209 * Check for "FRENCH " infection ;-) (actually this should
210 * be replaced with routine to check the hostname syntax in
211 * general). [ This check is still needed, even after the parse
212 * is fixed, because someone can send "SERVER :foo bar " ].
213 * Also, changed to check other "difficult" characters, now
214 * that parse lets all through... --msa
216 if (strlen(host) > HOSTLEN)
217 host[HOSTLEN] = '\0';
219 for (ch = host; *ch; ch++) {
220 if (*ch <= ' ' || *ch > '~')
223 if (*ch || !strchr(host, '.')) {
224 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
226 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
232 * A local server introduces a new server behind this link.
233 * Check if this is allowed according L:, H: and Q: lines.
236 return exit_client_msg(cptr, cptr, &me,
237 "No server info specified for %s", host);
239 * See if the newly found server is behind a guaranteed
240 * leaf (L-line). If so, close the link.
242 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
243 (!lhconf->port || (hop > lhconf->port)))
246 * L: lines normally come in pairs, here we try to
247 * make sure that the oldest link is squitted, not
251 if (timestamp <= cptr->serv->timestamp)
252 LHcptr = 0; /* Kill incoming server */
254 LHcptr = cptr; /* Squit ourselfs */
256 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
257 (lhconf->port && (hop > lhconf->port)))
259 struct Client *ac3ptr;
261 /* Look for net junction causing this: */
262 LHcptr = 0; /* incoming server */
263 if (*parv[5] != 'J') {
264 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
265 if (IsJunction(ac3ptr)) {
274 if (IsUnknown(cptr) || IsHandshake(cptr))
279 * A local link that is still in undefined state wants
280 * to be a SERVER. Check if this is allowed and change
281 * status accordingly...
284 * If there is more then one server on the same machine
285 * that we try to connect to, it could be that the /CONNECT
286 * <mask> caused this connect to be put at the wrong place
287 * in the hashtable. --Run
288 * Same thing for Unknown connections that first send NICK.
290 * Better check if the two strings are (caseless) identical
291 * and not mess with hash internals.
294 if (!EmptyString(cptr->name) &&
295 (IsUnknown(cptr) || IsHandshake(cptr)) &&
296 0 != ircd_strcmp(cptr->name, host))
297 hChangeClient(cptr, host);
298 ircd_strncpy(cptr->name, host, HOSTLEN);
299 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
300 cptr->hopcount = hop;
302 /* check connection rules */
303 if (0 != conf_eval_crule(host, CRULE_ALL)) {
304 ServerStats->is_ref++;
305 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cptr->name);
306 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
309 if (conf_check_server(cptr)) {
310 ++ServerStats->is_ref;
311 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
312 "from %s.", cptr->name);
313 return exit_client(cptr, cptr, &me, "No C:line");
320 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
321 ++ServerStats->is_ref;
323 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
324 "server %s", cptr->name);
325 return exit_client_msg(cptr, cptr, &me,
326 "Access denied. No conf line for server %s", cptr->name);
328 sendto_opmask_butone(0, SNO_OLDSNO, "General C: line active: No line "
329 "for server %s", cptr->name);
330 aconf = find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
332 sendto_opmask_butone(0, SNO_OLDSNO, "Neither C lines for server %s "
333 "nor \"general.undernet.org\"", cptr->name);
334 return exit_client_msg(cptr, cptr, &me, "No C lines for server %s", cptr->name);
338 #ifdef CRYPT_LINK_PASSWORD
339 /* passwd may be NULL. Head it off at the pass... */
341 encr = ircd_crypt(cptr->passwd, aconf->passed);
347 #endif /* CRYPT_LINK_PASSWORD */
349 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
350 ++ServerStats->is_ref;
351 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
353 return exit_client_msg(cptr, cptr, &me,
354 "No Access (passwd mismatch) %s", cptr->name);
356 #endif /* not GODMODE */
357 memset(cptr->passwd, 0, sizeof(cptr->passwd));
360 for (i = 0; i <= HighestFd; i++)
361 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
370 * We want to find IsConnecting() and IsHandshake() too,
372 * The second finds collisions with numeric representation of existing
373 * servers - these shouldn't happen anymore when all upgraded to 2.10.
376 while ((acptr = FindClient(host)) ||
377 (parc > 7 && (acptr = FindNServer(parv[6]))))
380 * This link is trying feed me a server that I already have
381 * access through another path
383 * Do not allow Uworld to do this.
384 * Do not allow servers that are juped.
385 * Do not allow servers that have older link timestamps
387 * Do not allow servers that use the same numeric as an existing
388 * server, but have a different name.
390 * If my ircd.conf sucks, I can try to connect to myself:
393 return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
395 * Detect wrong numeric.
397 if (0 != ircd_strcmp(acptr->name, host)) {
398 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
399 ":SERVER Numeric Collision: %s != %s",
401 return exit_client_msg(cptr, cptr, &me,
402 "NUMERIC collision between %s and %s."
403 " Is your server numeric correct ?", host, acptr->name);
406 * Kill our try, if we had one.
408 if (IsConnecting(acptr))
410 if (!active_lh_line && exit_client(cptr, acptr, &me,
411 "Just connected via another link") == CPTR_KILLED)
414 * We can have only ONE 'IsConnecting', 'IsHandshake' or
415 * 'IsServer', because new 'IsConnecting's are refused to
416 * the same server if we already had it.
421 * Avoid other nick collisions...
422 * This is a doubtfull test though, what else would it be
423 * when it has a server.name ?
425 else if (!IsServer(acptr) && !IsHandshake(acptr))
426 return exit_client_msg(cptr, cptr, &me,
427 "Nickname %s already exists!", host);
429 * Our new server might be a juped server,
430 * or someone trying abuse a second Uworld:
432 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
433 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
436 return exit_client(cptr, sptr, &me, acptr->info);
437 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
438 ":Received :%s SERVER %s from %s !?!", parv[0],
439 parv[1], cptr->name);
440 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
443 * Of course we find the handshake this link was before :)
445 else if (IsHandshake(acptr) && acptr == cptr)
448 * Here we have a server nick collision...
449 * We don't want to kill the link that was last /connected,
450 * but we neither want to kill a good (old) link.
451 * Therefor we kill the second youngest link.
455 struct Client* c2ptr = 0;
456 struct Client* c3ptr = acptr;
457 struct Client* ac2ptr;
458 struct Client* ac3ptr;
460 /* Search youngest link: */
461 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
462 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
466 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
467 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
470 if (timestamp > c3ptr->serv->timestamp)
473 c2ptr = acptr; /* Make sure they differ */
475 /* Search second youngest link: */
476 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
477 if (ac2ptr != c3ptr &&
478 ac2ptr->serv->timestamp >
479 (c2ptr ? c2ptr->serv->timestamp : timestamp))
483 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
484 if (ac2ptr != c3ptr &&
485 ac2ptr->serv->timestamp >
486 (c2ptr ? c2ptr->serv->timestamp : timestamp))
489 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
491 /* If timestamps are equal, decide which link to break
494 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
495 (c3ptr ? c3ptr->serv->timestamp : timestamp))
504 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
509 n2up = IsServer(sptr) ? sptr->name : me.name;
514 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
519 n3up = IsServer(sptr) ? sptr->name : me.name;
521 if (strcmp(n2, n2up) > 0)
523 if (strcmp(n3, n3up) > 0)
525 if (strcmp(n3, n2) > 0)
532 /* Now squit the second youngest link: */
534 return exit_new_server(cptr, sptr, host, timestamp,
535 "server %s already exists and is %ld seconds younger.",
536 host, (long)acptr->serv->timestamp - (long)timestamp);
537 else if (c2ptr->from == cptr || IsServer(sptr))
539 struct Client *killedptrfrom = c2ptr->from;
543 * If the L: or H: line also gets rid of this link,
544 * we sent just one squit.
546 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
549 * If breaking the loop here solves the L: or H:
550 * line problem, we don't squit that.
552 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
557 * If we still have a L: or H: line problem,
558 * we prefer to squit the new server, solving
559 * loop and L:/H: line problem with only one squit.
566 * If the new server was introduced by a server that caused a
567 * Ghost less then 20 seconds ago, this is probably also
568 * a Ghost... (20 seconds is more then enough because all
569 * SERVER messages are at the beginning of a net.burst). --Run
571 if (CurrentTime - cptr->serv->ghost < 20)
573 killedptrfrom = acptr->from;
574 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
577 else if (exit_client_msg(cptr, c2ptr, &me,
578 "Loop <-- %s (new link is %ld seconds younger)", host,
579 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
580 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
583 * Did we kill the incoming server off already ?
585 if (killedptrfrom == cptr)
592 if (LHcptr && a_kills_b_too(LHcptr, acptr))
594 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
603 * We can't believe it is a lagged server message
604 * when it directly connects to us...
605 * kill the older link at the ghost, rather then
606 * at the second youngest link, assuming it isn't
609 ghost = CurrentTime; /* Mark that it caused a ghost */
610 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
620 return exit_new_server(cptr, sptr, host, timestamp,
621 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
622 "Leaf-only link %s <- %s(%s), check L:",
624 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
628 int killed = a_kills_b_too(LHcptr, sptr);
629 if (active_lh_line < 3)
631 if (exit_client_msg(cptr, LHcptr, &me,
632 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
633 "Leaf-only link %s <- %s(%s), check L:",
635 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
640 ServerStats->is_ref++;
641 if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
645 * Did we kill the incoming server off already ?
655 * Server is informing about a new server behind
656 * this link. Create REMOTE server structure,
657 * add it to list and propagate word to my other
661 acptr = make_client(cptr, STAT_SERVER);
663 acptr->serv->prot = prot;
664 acptr->serv->timestamp = timestamp;
665 acptr->hopcount = hop;
666 ircd_strncpy(acptr->name, host, HOSTLEN);
667 ircd_strncpy(acptr->info, info, REALLEN);
668 acptr->serv->up = sptr;
669 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
670 /* Use cptr, because we do protocol 9 -> 10 translation
671 for numeric nicks ! */
672 SetServerYXX(cptr, acptr, parv[6]);
674 Count_newremoteserver(UserStats);
675 if (Protocol(acptr) < 10)
676 acptr->flags |= FLAGS_TS8;
677 add_client_to_list(acptr);
682 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
683 sptr->name, acptr->name);
687 * Old sendto_serv_but_one() call removed because we now need to send
688 * different names to different servers (domain name matching).
690 * Personally, I think this is bogus; it's a feature we don't use here.
693 for (i = 0; i <= HighestFd; i++)
695 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
696 bcptr == cptr || IsMe(bcptr))
698 if (0 == match(me.name, acptr->name))
700 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
701 acptr->name, hop + 1, parv[4], parv[5], NumServCap(acptr),
707 if (IsUnknown(cptr) || IsHandshake(cptr))
710 cptr->serv->timestamp = timestamp;
711 cptr->serv->prot = prot;
712 cptr->serv->ghost = ghost;
713 SetServerYXX(cptr, cptr, parv[6]);
714 if (start_timestamp > OLDEST_TS)
716 #ifndef RELIABLE_CLOCK
718 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
719 "others start time: %Tu", me.serv->timestamp,
721 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
722 "received timestamp: %Tu ; difference %ld",
723 recv_time, timestamp, timestamp - recv_time);
725 if (start_timestamp < me.serv->timestamp)
727 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
728 "%Tu < %Tu", start_timestamp, me.serv->timestamp);
729 me.serv->timestamp = start_timestamp;
730 TSoffset += timestamp - recv_time;
731 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
732 (int)(timestamp - recv_time));
734 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
735 cptr->serv->timestamp = TStime();
737 else if (timestamp != recv_time)
740 * Equal start times, we have a collision. Let the connected-to server
741 * decide. This assumes leafs issue more than half of the connection
745 cptr->serv->timestamp = TStime();
746 else if (IsHandshake(cptr))
748 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
749 (int)(timestamp - recv_time));
750 TSoffset += timestamp - recv_time;
753 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
754 if (start_timestamp < me.serv->timestamp)
755 me.serv->timestamp = start_timestamp;
757 cptr->serv->timestamp = TStime();
761 ret = server_estab(cptr, aconf, ajupe);
765 #ifdef RELIABLE_CLOCK
766 if (abs(cptr->serv->timestamp - recv_time) > 30)
768 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
769 "timestamp-clock difference of %Td seconds! "
770 "Used SETTIME to correct this.",
771 timestamp - recv_time);
772 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), me.name);
780 * ms_server - server message handler
782 * parv[0] = sender prefix
783 * parv[1] = servername
785 * parv[3] = start timestamp
786 * parv[4] = link timestamp
787 * parv[5] = major protocol version: P09/P10
788 * parv[parc-1] = serverinfo
790 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
791 * numeric nick mask of this server.
792 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
793 * parv[8] = %<lastmod> - optional parameter only present if there's an
794 * outstanding JUPE; specifies the JUPE's lastmod field
796 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
800 char info[REALLEN + 1];
802 struct Client* acptr;
803 struct Client* bcptr;
804 struct Client* LHcptr = 0;
805 struct ConfItem* aconf = 0;
806 struct ConfItem* lhconf = 0;
807 struct Jupe* ajupe = 0;
810 int active_lh_line = 0;
812 time_t start_timestamp;
813 time_t timestamp = 0;
818 if (IsUserPort(cptr))
819 return exit_client_msg(cptr, cptr, &me,
820 "Cannot connect a server to a user port");
822 recv_time = TStime();
826 return need_more_params(sptr, "SERVER");
827 return exit_client(cptr, cptr, &me, "Need more parameters");
834 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
835 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
837 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
840 prot = atoi(parv[5] + 1);
841 if (prot > atoi(MAJOR_PROTOCOL))
842 prot = atoi(MAJOR_PROTOCOL);
844 * Because the previous test is only in 2.10, the following is needed
845 * till all servers are 2.10:
847 if (IsServer(cptr) && prot > Protocol(cptr))
848 prot = Protocol(cptr);
850 start_timestamp = atoi(parv[3]);
851 timestamp = atoi(parv[4]);
852 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
853 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
854 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
856 return exit_client_msg(cptr, sptr, &me,
857 "Bogus timestamps (%s %s)", parv[3], parv[4]);
859 ircd_strncpy(info, parv[parc - 1], REALLEN);
860 info[REALLEN] = '\0';
861 if (prot < atoi(MINOR_PROTOCOL)) {
862 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
863 "(%s) from %s", parv[5], cptr->name);
864 return exit_new_server(cptr, sptr, host, timestamp,
865 "Incompatible protocol: %s", parv[5]);
867 if (parc > 9 && *parv[8] == '%')
868 lastmod = atoi(parv[8] + 1);
869 /* If there's a jupe that matches, and it's a global jupe, and the
870 * introducer didn't indicate it knew of the jupe or has an older
871 * version of the jupe, and the connection isn't in a BURST, resynch
874 if ((ajupe = jupe_find(host)) && !JupeIsLocal(ajupe) &&
875 JupeLastMod(ajupe) > lastmod && !IsBurstOrBurstAck(cptr))
876 jupe_resend(cptr, ajupe);
878 * Check for "FRENCH " infection ;-) (actually this should
879 * be replaced with routine to check the hostname syntax in
880 * general). [ This check is still needed, even after the parse
881 * is fixed, because someone can send "SERVER :foo bar " ].
882 * Also, changed to check other "difficult" characters, now
883 * that parse lets all through... --msa
885 if (strlen(host) > HOSTLEN)
886 host[HOSTLEN] = '\0';
887 for (ch = host; *ch; ch++)
888 if (*ch <= ' ' || *ch > '~')
890 if (*ch || !strchr(host, '.')) {
891 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
893 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
899 * A local server introduces a new server behind this link.
900 * Check if this is allowed according L:, H: and Q: lines.
903 return exit_client_msg(cptr, cptr, &me,
904 "No server info specified for %s", host);
906 * See if the newly found server is behind a guaranteed
907 * leaf (L-line). If so, close the link.
909 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
910 (!lhconf->port || (hop > lhconf->port)))
913 * L: lines normally come in pairs, here we try to
914 * make sure that the oldest link is squitted, not
918 if (timestamp <= cptr->serv->timestamp)
919 LHcptr = 0; /* Kill incoming server */
921 LHcptr = cptr; /* Squit ourselfs */
923 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
924 (lhconf->port && (hop > lhconf->port)))
926 struct Client *ac3ptr;
928 /* Look for net junction causing this: */
929 LHcptr = 0; /* incoming server */
930 if (*parv[5] != 'J') {
931 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
932 if (IsJunction(ac3ptr)) {
941 if (IsUnknown(cptr) || IsHandshake(cptr))
946 * A local link that is still in undefined state wants
947 * to be a SERVER. Check if this is allowed and change
948 * status accordingly...
951 * If there is more then one server on the same machine
952 * that we try to connect to, it could be that the /CONNECT
953 * <mask> caused this connect to be put at the wrong place
954 * in the hashtable. --Run
955 * Same thing for Unknown connections that first send NICK.
957 * Better check if the two strings are (caseless) identical
958 * and not mess with hash internals.
961 if ((!(EmptyString(cptr->name)))
962 && (IsUnknown(cptr) || IsHandshake(cptr))
963 && 0 != ircd_strcmp(cptr->name, host))
964 hChangeClient(cptr, host);
965 ircd_strncpy(cptr->name, host, HOSTLEN);
966 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
967 cptr->hopcount = hop;
969 /* check connection rules */
970 if (0 != conf_eval_crule(host, CRULE_ALL)) {
971 ServerStats->is_ref++;
972 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cptr->name);
973 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
975 if (conf_check_server(cptr)) {
976 ++ServerStats->is_ref;
977 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
978 "from %s.", cptr->name);
979 return exit_client(cptr, cptr, &me, "No C conf lines");
986 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
987 ++ServerStats->is_ref;
989 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
990 "server %s", cptr->name);
991 return exit_client_msg(cptr, cptr, &me,
992 "Access denied. No conf line for server %s", cptr->name);
994 sendto_opmask_butone(0, SNO_OLDSNO, "General C line active: No line "
995 "for server %s", cptr->name);
997 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
999 sendto_opmask_butone(0, SNO_OLDSNO, "Neither C lines for server %s "
1000 "nor \"general.undernet.org\"", cptr->name);
1001 return exit_client_msg(cptr, cptr, &me,
1002 "No C lines for server %s", cptr->name);
1004 #endif /* GODMODE */
1006 #ifdef CRYPT_LINK_PASSWORD
1007 /* passwd may be NULL. Head it off at the pass... */
1010 encr = ircd_crypt(cptr->passwd, aconf->passwd);
1015 encr = cptr->passwd;
1016 #endif /* CRYPT_LINK_PASSWORD */
1018 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1019 ++ServerStats->is_ref;
1020 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
1022 return exit_client_msg(cptr, cptr, &me,
1023 "No Access (passwd mismatch) %s", cptr->name);
1025 #endif /* not GODMODE */
1026 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1029 for (i = 0; i <= HighestFd; i++)
1030 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1039 * We want to find IsConnecting() and IsHandshake() too,
1041 * The second finds collisions with numeric representation of existing
1042 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1045 while ((acptr = FindClient(host)) ||
1046 (parc > 7 && (acptr = FindNServer(parv[6]))))
1049 * This link is trying feed me a server that I already have
1050 * access through another path
1052 * Do not allow Uworld to do this.
1053 * Do not allow servers that are juped.
1054 * Do not allow servers that have older link timestamps
1056 * Do not allow servers that use the same numeric as an existing
1057 * server, but have a different name.
1059 * If my ircd.conf sucks, I can try to connect to myself:
1062 return exit_client_msg(cptr, cptr, &me,
1063 "nick collision with me, check server number in M:? (%s)", host);
1065 * Detect wrong numeric.
1067 if (0 != ircd_strcmp(acptr->name, host))
1069 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1070 ":SERVER Numeric Collision: %s != %s", acptr->name,
1072 return exit_client_msg(cptr, cptr, &me,
1073 "NUMERIC collision between %s and %s."
1074 " Is your server numeric correct ?", host, acptr->name);
1077 * Kill our try, if we had one.
1079 if (IsConnecting(acptr))
1081 if (!active_lh_line && exit_client(cptr, acptr, &me,
1082 "Just connected via another link") == CPTR_KILLED)
1085 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1086 * 'IsServer', because new 'IsConnecting's are refused to
1087 * the same server if we already had it.
1092 * Avoid other nick collisions...
1093 * This is a doubtfull test though, what else would it be
1094 * when it has a server.name ?
1096 else if (!IsServer(acptr) && !IsHandshake(acptr))
1097 return exit_client_msg(cptr, cptr, &me,
1098 "Nickname %s already exists!", host);
1100 * Our new server might be a juped server,
1101 * or someone trying abuse a second Uworld:
1103 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1104 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1106 if (!IsServer(sptr))
1107 return exit_client(cptr, sptr, &me, acptr->info);
1108 sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1109 "from %s !?!", parv[0], parv[1], cptr->name);
1110 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1113 * Of course we find the handshake this link was before :)
1115 else if (IsHandshake(acptr) && acptr == cptr)
1118 * Here we have a server nick collision...
1119 * We don't want to kill the link that was last /connected,
1120 * but we neither want to kill a good (old) link.
1121 * Therefor we kill the second youngest link.
1125 struct Client* c2ptr = 0;
1126 struct Client* c3ptr = acptr;
1127 struct Client* ac2ptr;
1128 struct Client* ac3ptr;
1130 /* Search youngest link: */
1131 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1132 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1136 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1137 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1140 if (timestamp > c3ptr->serv->timestamp)
1143 c2ptr = acptr; /* Make sure they differ */
1145 /* Search second youngest link: */
1146 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1147 if (ac2ptr != c3ptr &&
1148 ac2ptr->serv->timestamp >
1149 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1153 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1154 if (ac2ptr != c3ptr &&
1155 ac2ptr->serv->timestamp >
1156 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1159 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1161 /* If timestamps are equal, decide which link to break
1164 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1165 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1174 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1179 n2up = IsServer(sptr) ? sptr->name : me.name;
1184 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1189 n3up = IsServer(sptr) ? sptr->name : me.name;
1191 if (strcmp(n2, n2up) > 0)
1193 if (strcmp(n3, n3up) > 0)
1195 if (strcmp(n3, n2) > 0)
1202 /* Now squit the second youngest link: */
1204 return exit_new_server(cptr, sptr, host, timestamp,
1205 "server %s already exists and is %ld seconds younger.",
1206 host, (long)acptr->serv->timestamp - (long)timestamp);
1207 else if (c2ptr->from == cptr || IsServer(sptr))
1209 struct Client *killedptrfrom = c2ptr->from;
1213 * If the L: or H: line also gets rid of this link,
1214 * we sent just one squit.
1216 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1219 * If breaking the loop here solves the L: or H:
1220 * line problem, we don't squit that.
1222 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1227 * If we still have a L: or H: line problem,
1228 * we prefer to squit the new server, solving
1229 * loop and L:/H: line problem with only one squit.
1236 * If the new server was introduced by a server that caused a
1237 * Ghost less then 20 seconds ago, this is probably also
1238 * a Ghost... (20 seconds is more then enough because all
1239 * SERVER messages are at the beginning of a net.burst). --Run
1241 if (CurrentTime - cptr->serv->ghost < 20)
1243 killedptrfrom = acptr->from;
1244 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1247 else if (exit_client_msg(cptr, c2ptr, &me,
1248 "Loop <-- %s (new link is %ld seconds younger)", host,
1249 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1250 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1253 * Did we kill the incoming server off already ?
1255 if (killedptrfrom == cptr)
1262 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1264 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1273 * We can't believe it is a lagged server message
1274 * when it directly connects to us...
1275 * kill the older link at the ghost, rather then
1276 * at the second youngest link, assuming it isn't
1279 ghost = CurrentTime; /* Mark that it caused a ghost */
1280 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1290 return exit_new_server(cptr, sptr, host, timestamp,
1291 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1293 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1297 int killed = a_kills_b_too(LHcptr, sptr);
1298 if (active_lh_line < 3)
1300 if (exit_client_msg(cptr, LHcptr, &me,
1301 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1303 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1308 ServerStats->is_ref++;
1309 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1313 * Did we kill the incoming server off already ?
1323 * Server is informing about a new server behind
1324 * this link. Create REMOTE server structure,
1325 * add it to list and propagate word to my other
1329 acptr = make_client(cptr, STAT_SERVER);
1331 acptr->serv->prot = prot;
1332 acptr->serv->timestamp = timestamp;
1333 acptr->hopcount = hop;
1334 ircd_strncpy(acptr->name, host, HOSTLEN);
1335 ircd_strncpy(acptr->info, info, REALLEN);
1336 acptr->serv->up = sptr;
1337 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1338 /* Use cptr, because we do protocol 9 -> 10 translation
1339 for numeric nicks ! */
1340 SetServerYXX(cptr, acptr, parv[6]);
1342 Count_newremoteserver(UserStats);
1343 if (Protocol(acptr) < 10)
1344 acptr->flags |= FLAGS_TS8;
1345 add_client_to_list(acptr);
1347 if (*parv[5] == 'J')
1350 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1351 sptr->name, acptr->name);
1355 * Old sendto_serv_but_one() call removed because we now need to send
1356 * different names to different servers (domain name matching).
1358 for (i = 0; i <= HighestFd; i++)
1360 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1361 bcptr == cptr || IsMe(bcptr))
1363 if (0 == match(me.name, acptr->name))
1365 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1366 acptr->name, hop + 1, parv[4], parv[5], NumServCap(acptr),
1372 if (IsUnknown(cptr) || IsHandshake(cptr))
1375 cptr->serv->timestamp = timestamp;
1376 cptr->serv->prot = prot;
1377 cptr->serv->ghost = ghost;
1378 SetServerYXX(cptr, cptr, parv[6]);
1379 if (start_timestamp > OLDEST_TS)
1381 #ifndef RELIABLE_CLOCK
1383 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
1384 "others start time: %Tu", me.serv->timestamp,
1386 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
1387 "received timestamp: %Tu ; difference %ld",
1388 recv_time, timestamp, timestamp - recv_time);
1390 if (start_timestamp < me.serv->timestamp)
1392 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1393 "%Tu < %Tu", start_timestamp, me.serv->timestamp);
1394 me.serv->timestamp = start_timestamp;
1395 TSoffset += timestamp - recv_time;
1396 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1397 (int)(timestamp - recv_time));
1399 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1400 cptr->serv->timestamp = TStime();
1402 else if (timestamp != recv_time)
1405 * Equal start times, we have a collision. Let the connected-to server
1406 * decide. This assumes leafs issue more than half of the connection
1409 if (IsUnknown(cptr))
1410 cptr->serv->timestamp = TStime();
1411 else if (IsHandshake(cptr))
1413 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1414 (int)(timestamp - recv_time));
1415 TSoffset += timestamp - recv_time;
1418 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
1419 if (start_timestamp < me.serv->timestamp)
1420 me.serv->timestamp = start_timestamp;
1421 if (IsUnknown(cptr))
1422 cptr->serv->timestamp = TStime();
1426 ret = server_estab(cptr, aconf, ajupe);
1430 #ifdef RELIABLE_CLOCK
1431 if (abs(cptr->serv->timestamp - recv_time) > 30)
1433 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1434 "timestamp-clock difference of %Td seconds! Used "
1435 "SETTIME to correct this.", timestamp - recv_time);
1436 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), me.name);
1448 * parv[0] = sender prefix
1449 * parv[1] = servername
1450 * parv[2] = hopcount
1451 * parv[3] = start timestamp
1452 * parv[4] = link timestamp
1453 * parv[5] = major protocol version: P09/P10
1454 * parv[parc-1] = serverinfo
1456 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1457 * numeric nick mask of this server.
1458 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1460 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1464 char info[REALLEN + 1];
1466 struct Client* acptr;
1467 struct Client* bcptr;
1468 struct Client* LHcptr = 0;
1469 struct ConfItem* aconf = 0;
1470 struct ConfItem* lhconf = 0;
1471 struct Jupe* ajupe = 0;
1474 int active_lh_line = 0;
1475 unsigned short prot;
1476 time_t start_timestamp;
1477 time_t timestamp = 0;
1483 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1487 if (IsUserPort(cptr))
1488 return exit_client_msg(cptr, cptr, &me,
1489 "You cannot connect a server to a user port; connect to %s port %u",
1490 me.name, server_port);
1492 recv_time = TStime();
1496 return need_more_params(sptr, "SERVER");
1497 return exit_client(cptr, cptr, &me, "Need more parameters");
1503 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1504 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1506 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1509 prot = atoi(parv[5] + 1);
1510 if (prot > atoi(MAJOR_PROTOCOL))
1511 prot = atoi(MAJOR_PROTOCOL);
1513 * Because the previous test is only in 2.10, the following is needed
1514 * till all servers are 2.10:
1516 if (IsServer(cptr) && prot > Protocol(cptr))
1517 prot = Protocol(cptr);
1518 hop = atoi(parv[2]);
1519 start_timestamp = atoi(parv[3]);
1520 timestamp = atoi(parv[4]);
1521 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1522 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1523 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1525 return exit_client_msg(cptr, sptr, &me,
1526 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1528 ircd_strncpy(info, parv[parc - 1], REALLEN);
1529 info[REALLEN] = '\0';
1530 if (prot < atoi(MINOR_PROTOCOL)) {
1531 sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1532 parv[5], cptr->name);
1533 return exit_new_server(cptr, sptr, host, timestamp,
1534 "Incompatible protocol: %s", parv[5]);
1537 * Check for "FRENCH " infection ;-) (actually this should
1538 * be replaced with routine to check the hostname syntax in
1539 * general). [ This check is still needed, even after the parse
1540 * is fixed, because someone can send "SERVER :foo bar " ].
1541 * Also, changed to check other "difficult" characters, now
1542 * that parse lets all through... --msa
1544 if (strlen(host) > HOSTLEN)
1545 host[HOSTLEN] = '\0';
1546 for (ch = host; *ch; ch++)
1547 if (*ch <= ' ' || *ch > '~')
1549 if (*ch || !strchr(host, '.'))
1551 sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1552 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1558 * A local server introduces a new server behind this link.
1559 * Check if this is allowed according L:, H: and Q: lines.
1561 if (info[0] == '\0')
1562 return exit_client_msg(cptr, cptr, &me,
1563 "No server info specified for %s", host);
1565 * See if the newly found server is behind a guaranteed
1566 * leaf (L-line). If so, close the link.
1568 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1569 (!lhconf->port || (hop > lhconf->port)))
1572 * L: lines normally come in pairs, here we try to
1573 * make sure that the oldest link is squitted, not
1577 if (timestamp <= cptr->serv->timestamp)
1578 LHcptr = 0; /* Kill incoming server */
1580 LHcptr = cptr; /* Squit ourselfs */
1582 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1583 (lhconf->port && (hop > lhconf->port)))
1585 struct Client *ac3ptr;
1587 /* Look for net junction causing this: */
1588 LHcptr = 0; /* incoming server */
1589 if (*parv[5] != 'J') {
1590 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1591 if (IsJunction(ac3ptr)) {
1600 if (IsUnknown(cptr) || IsHandshake(cptr))
1605 * A local link that is still in undefined state wants
1606 * to be a SERVER. Check if this is allowed and change
1607 * status accordingly...
1610 * If there is more then one server on the same machine
1611 * that we try to connect to, it could be that the /CONNECT
1612 * <mask> caused this connect to be put at the wrong place
1613 * in the hashtable. --Run
1614 * Same thing for Unknown connections that first send NICK.
1616 * Better check if the two strings are (caseless) identical
1617 * and not mess with hash internals.
1620 if ((!(EmptyString(cptr->name)))
1621 && (IsUnknown(cptr) || IsHandshake(cptr))
1622 && 0 != ircd_strcmp(cptr->name, host))
1623 hChangeClient(cptr, host);
1624 ircd_strncpy(cptr->name, host, HOSTLEN);
1625 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1626 cptr->hopcount = hop;
1628 /* check connection rules */
1629 if (0 != conf_eval_crule(host, CRULE_ALL)) {
1630 ServerStats->is_ref++;
1631 sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1632 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1634 if (conf_check_server(cptr)) {
1635 ++ServerStats->is_ref;
1636 sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1637 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1644 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1645 ++ServerStats->is_ref;
1647 sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1648 return exit_client_msg(cptr, cptr, &me,
1649 "Access denied. No conf line for server %s", cptr->name);
1651 sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1653 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1655 sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1656 "\"general.undernet.org\"", cptr->name);
1657 return exit_client_msg(cptr, cptr, &me,
1658 "No C/N lines for server %s", cptr->name);
1660 #endif /* GODMODE */
1662 #ifdef CRYPT_LINK_PASSWORD
1663 /* passwd may be NULL. Head it off at the pass... */
1666 encr = ircd_crypt(cptr->passwd, aconf->passwd);
1671 encr = cptr->passwd;
1672 #endif /* CRYPT_LINK_PASSWORD */
1674 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1675 ++ServerStats->is_ref;
1676 sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1677 return exit_client_msg(cptr, cptr, &me,
1678 "No Access (passwd mismatch) %s", cptr->name);
1680 #endif /* not GODMODE */
1681 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1684 for (i = 0; i <= HighestFd; i++)
1685 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1694 * We want to find IsConnecting() and IsHandshake() too,
1696 * The second finds collisions with numeric representation of existing
1697 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1700 while ((acptr = FindClient(host)) ||
1701 (parc > 7 && (acptr = FindNServer(parv[6]))))
1704 * This link is trying feed me a server that I already have
1705 * access through another path
1707 * Do not allow Uworld to do this.
1708 * Do not allow servers that are juped.
1709 * Do not allow servers that have older link timestamps
1711 * Do not allow servers that use the same numeric as an existing
1712 * server, but have a different name.
1714 * If my ircd.conf sucks, I can try to connect to myself:
1717 return exit_client_msg(cptr, cptr, &me,
1718 "nick collision with me, check server number in M:? (%s)", host);
1720 * Detect wrong numeric.
1722 if (0 != ircd_strcmp(acptr->name, host))
1724 sendto_serv_butone(cptr, /* XXX DEAD */
1725 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1726 me.name, acptr->name, host);
1727 return exit_client_msg(cptr, cptr, &me,
1728 "NUMERIC collision between %s and %s."
1729 " Is your server numeric correct ?", host, acptr->name);
1732 * Kill our try, if we had one.
1734 if (IsConnecting(acptr))
1736 if (!active_lh_line && exit_client(cptr, acptr, &me,
1737 "Just connected via another link") == CPTR_KILLED)
1740 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1741 * 'IsServer', because new 'IsConnecting's are refused to
1742 * the same server if we already had it.
1747 * Avoid other nick collisions...
1748 * This is a doubtfull test though, what else would it be
1749 * when it has a server.name ?
1751 else if (!IsServer(acptr) && !IsHandshake(acptr))
1752 return exit_client_msg(cptr, cptr, &me,
1753 "Nickname %s already exists!", host);
1755 * Our new server might be a juped server,
1756 * or someone trying abuse a second Uworld:
1758 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1759 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1761 if (!IsServer(sptr))
1762 return exit_client(cptr, sptr, &me, acptr->info);
1763 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1764 me.name, parv[0], parv[1], cptr->name);
1765 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1768 * Of course we find the handshake this link was before :)
1770 else if (IsHandshake(acptr) && acptr == cptr)
1773 * Here we have a server nick collision...
1774 * We don't want to kill the link that was last /connected,
1775 * but we neither want to kill a good (old) link.
1776 * Therefor we kill the second youngest link.
1780 struct Client* c2ptr = 0;
1781 struct Client* c3ptr = acptr;
1782 struct Client* ac2ptr;
1783 struct Client* ac3ptr;
1785 /* Search youngest link: */
1786 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1787 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1791 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1792 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1795 if (timestamp > c3ptr->serv->timestamp)
1798 c2ptr = acptr; /* Make sure they differ */
1800 /* Search second youngest link: */
1801 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1802 if (ac2ptr != c3ptr &&
1803 ac2ptr->serv->timestamp >
1804 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1808 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1809 if (ac2ptr != c3ptr &&
1810 ac2ptr->serv->timestamp >
1811 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1814 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1816 /* If timestamps are equal, decide which link to break
1819 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1820 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1829 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1834 n2up = IsServer(sptr) ? sptr->name : me.name;
1839 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1844 n3up = IsServer(sptr) ? sptr->name : me.name;
1846 if (strcmp(n2, n2up) > 0)
1848 if (strcmp(n3, n3up) > 0)
1850 if (strcmp(n3, n2) > 0)
1857 /* Now squit the second youngest link: */
1859 return exit_new_server(cptr, sptr, host, timestamp,
1860 "server %s already exists and is %ld seconds younger.",
1861 host, (long)acptr->serv->timestamp - (long)timestamp);
1862 else if (c2ptr->from == cptr || IsServer(sptr))
1864 struct Client *killedptrfrom = c2ptr->from;
1868 * If the L: or H: line also gets rid of this link,
1869 * we sent just one squit.
1871 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1874 * If breaking the loop here solves the L: or H:
1875 * line problem, we don't squit that.
1877 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1882 * If we still have a L: or H: line problem,
1883 * we prefer to squit the new server, solving
1884 * loop and L:/H: line problem with only one squit.
1891 * If the new server was introduced by a server that caused a
1892 * Ghost less then 20 seconds ago, this is probably also
1893 * a Ghost... (20 seconds is more then enough because all
1894 * SERVER messages are at the beginning of a net.burst). --Run
1896 if (CurrentTime - cptr->serv->ghost < 20)
1898 killedptrfrom = acptr->from;
1899 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1902 else if (exit_client_msg(cptr, c2ptr, &me,
1903 "Loop <-- %s (new link is %ld seconds younger)", host,
1904 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1905 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1908 * Did we kill the incoming server off already ?
1910 if (killedptrfrom == cptr)
1917 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1919 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1928 * We can't believe it is a lagged server message
1929 * when it directly connects to us...
1930 * kill the older link at the ghost, rather then
1931 * at the second youngest link, assuming it isn't
1934 ghost = CurrentTime; /* Mark that it caused a ghost */
1935 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1945 return exit_new_server(cptr, sptr, host, timestamp,
1946 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1948 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1952 int killed = a_kills_b_too(LHcptr, sptr);
1953 if (active_lh_line < 3)
1955 if (exit_client_msg(cptr, LHcptr, &me,
1956 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1958 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1963 ServerStats->is_ref++;
1964 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1968 * Did we kill the incoming server off already ?
1978 * Server is informing about a new server behind
1979 * this link. Create REMOTE server structure,
1980 * add it to list and propagate word to my other
1984 acptr = make_client(cptr, STAT_SERVER);
1986 acptr->serv->prot = prot;
1987 acptr->serv->timestamp = timestamp;
1988 acptr->hopcount = hop;
1989 ircd_strncpy(acptr->name, host, HOSTLEN);
1990 ircd_strncpy(acptr->info, info, REALLEN);
1991 acptr->serv->up = sptr;
1992 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1993 /* Use cptr, because we do protocol 9 -> 10 translation
1994 for numeric nicks ! */
1995 SetServerYXX(cptr, acptr, parv[6]);
1997 Count_newremoteserver(UserStats);
1998 if (Protocol(acptr) < 10)
1999 acptr->flags |= FLAGS_TS8;
2000 add_client_to_list(acptr);
2002 if (*parv[5] == 'J')
2005 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
2006 sptr->name, acptr->name);
2010 * Old sendto_serv_but_one() call removed because we now need to send
2011 * different names to different servers (domain name matching).
2013 for (i = 0; i <= HighestFd; i++)
2015 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
2016 bcptr == cptr || IsMe(bcptr))
2018 if (0 == match(me.name, acptr->name))
2020 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
2021 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
2022 NumServCap(acptr), acptr->info);
2027 if (IsUnknown(cptr) || IsHandshake(cptr))
2030 cptr->serv->timestamp = timestamp;
2031 cptr->serv->prot = prot;
2032 cptr->serv->ghost = ghost;
2033 SetServerYXX(cptr, cptr, parv[6]);
2034 if (start_timestamp > OLDEST_TS)
2036 #ifndef RELIABLE_CLOCK
2038 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
2039 TIME_T_FMT, me.serv->timestamp, start_timestamp);
2040 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
2041 TIME_T_FMT " ; difference %ld",
2042 recv_time, timestamp, timestamp - recv_time);
2044 if (start_timestamp < me.serv->timestamp)
2046 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
2047 start_timestamp, me.serv->timestamp);
2048 me.serv->timestamp = start_timestamp;
2049 TSoffset += timestamp - recv_time;
2050 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
2052 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
2053 cptr->serv->timestamp = TStime();
2055 else if (timestamp != recv_time)
2058 * Equal start times, we have a collision. Let the connected-to server
2059 * decide. This assumes leafs issue more than half of the connection
2062 if (IsUnknown(cptr))
2063 cptr->serv->timestamp = TStime();
2064 else if (IsHandshake(cptr))
2066 sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
2067 (int)(timestamp - recv_time));
2068 TSoffset += timestamp - recv_time;
2071 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2072 if (start_timestamp < me.serv->timestamp)
2073 me.serv->timestamp = start_timestamp;
2074 if (IsUnknown(cptr))
2075 cptr->serv->timestamp = TStime();
2079 ret = server_estab(cptr, aconf); /* XXX DEAD */
2083 #ifdef RELIABLE_CLOCK
2084 if (abs(cptr->serv->timestamp - recv_time) > 30)
2086 sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2087 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2088 " this.", timestamp - recv_time);
2089 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2090 me.name, TStime(), me.name);