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 return 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... */
342 salt[0] = aconf->passwd[0];
343 salt[1] = aconf->passwd[1];
345 encr = ircd_crypt(cptr->passwd, salt);
351 #endif /* CRYPT_LINK_PASSWORD */
353 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
354 ++ServerStats->is_ref;
355 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
357 return exit_client_msg(cptr, cptr, &me,
358 "No Access (passwd mismatch) %s", cptr->name);
360 #endif /* not GODMODE */
361 memset(cptr->passwd, 0, sizeof(cptr->passwd));
364 for (i = 0; i <= HighestFd; i++)
365 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
374 * We want to find IsConnecting() and IsHandshake() too,
376 * The second finds collisions with numeric representation of existing
377 * servers - these shouldn't happen anymore when all upgraded to 2.10.
380 while ((acptr = FindClient(host)) ||
381 (parc > 7 && (acptr = FindNServer(parv[6]))))
384 * This link is trying feed me a server that I already have
385 * access through another path
387 * Do not allow Uworld to do this.
388 * Do not allow servers that are juped.
389 * Do not allow servers that have older link timestamps
391 * Do not allow servers that use the same numeric as an existing
392 * server, but have a different name.
394 * If my ircd.conf sucks, I can try to connect to myself:
397 return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
399 * Detect wrong numeric.
401 if (0 != ircd_strcmp(acptr->name, host)) {
402 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
403 ":SERVER Numeric Collision: %s != %s",
405 return exit_client_msg(cptr, cptr, &me,
406 "NUMERIC collision between %s and %s."
407 " Is your server numeric correct ?", host, acptr->name);
410 * Kill our try, if we had one.
412 if (IsConnecting(acptr))
414 if (!active_lh_line && exit_client(cptr, acptr, &me,
415 "Just connected via another link") == CPTR_KILLED)
418 * We can have only ONE 'IsConnecting', 'IsHandshake' or
419 * 'IsServer', because new 'IsConnecting's are refused to
420 * the same server if we already had it.
425 * Avoid other nick collisions...
426 * This is a doubtfull test though, what else would it be
427 * when it has a server.name ?
429 else if (!IsServer(acptr) && !IsHandshake(acptr))
430 return exit_client_msg(cptr, cptr, &me,
431 "Nickname %s already exists!", host);
433 * Our new server might be a juped server,
434 * or someone trying abuse a second Uworld:
436 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
437 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
440 return exit_client(cptr, sptr, &me, acptr->info);
441 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
442 ":Received :%s SERVER %s from %s !?!", parv[0],
443 parv[1], cptr->name);
444 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
447 * Of course we find the handshake this link was before :)
449 else if (IsHandshake(acptr) && acptr == cptr)
452 * Here we have a server nick collision...
453 * We don't want to kill the link that was last /connected,
454 * but we neither want to kill a good (old) link.
455 * Therefor we kill the second youngest link.
459 struct Client* c2ptr = 0;
460 struct Client* c3ptr = acptr;
461 struct Client* ac2ptr;
462 struct Client* ac3ptr;
464 /* Search youngest link: */
465 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
466 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
470 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
471 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
474 if (timestamp > c3ptr->serv->timestamp)
477 c2ptr = acptr; /* Make sure they differ */
479 /* Search second youngest link: */
480 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
481 if (ac2ptr != c3ptr &&
482 ac2ptr->serv->timestamp >
483 (c2ptr ? c2ptr->serv->timestamp : timestamp))
487 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
488 if (ac2ptr != c3ptr &&
489 ac2ptr->serv->timestamp >
490 (c2ptr ? c2ptr->serv->timestamp : timestamp))
493 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
495 /* If timestamps are equal, decide which link to break
498 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
499 (c3ptr ? c3ptr->serv->timestamp : timestamp))
508 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
513 n2up = IsServer(sptr) ? sptr->name : me.name;
518 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
523 n3up = IsServer(sptr) ? sptr->name : me.name;
525 if (strcmp(n2, n2up) > 0)
527 if (strcmp(n3, n3up) > 0)
529 if (strcmp(n3, n2) > 0)
536 /* Now squit the second youngest link: */
538 return exit_new_server(cptr, sptr, host, timestamp,
539 "server %s already exists and is %ld seconds younger.",
540 host, (long)acptr->serv->timestamp - (long)timestamp);
541 else if (c2ptr->from == cptr || IsServer(sptr))
543 struct Client *killedptrfrom = c2ptr->from;
547 * If the L: or H: line also gets rid of this link,
548 * we sent just one squit.
550 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
553 * If breaking the loop here solves the L: or H:
554 * line problem, we don't squit that.
556 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
561 * If we still have a L: or H: line problem,
562 * we prefer to squit the new server, solving
563 * loop and L:/H: line problem with only one squit.
570 * If the new server was introduced by a server that caused a
571 * Ghost less then 20 seconds ago, this is probably also
572 * a Ghost... (20 seconds is more then enough because all
573 * SERVER messages are at the beginning of a net.burst). --Run
575 if (CurrentTime - cptr->serv->ghost < 20)
577 killedptrfrom = acptr->from;
578 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
581 else if (exit_client_msg(cptr, c2ptr, &me,
582 "Loop <-- %s (new link is %ld seconds younger)", host,
583 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
584 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
587 * Did we kill the incoming server off already ?
589 if (killedptrfrom == cptr)
596 if (LHcptr && a_kills_b_too(LHcptr, acptr))
598 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
607 * We can't believe it is a lagged server message
608 * when it directly connects to us...
609 * kill the older link at the ghost, rather then
610 * at the second youngest link, assuming it isn't
613 ghost = CurrentTime; /* Mark that it caused a ghost */
614 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
624 return exit_new_server(cptr, sptr, host, timestamp,
625 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
626 "Leaf-only link %s <- %s(%s), check L:",
628 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
632 int killed = a_kills_b_too(LHcptr, sptr);
633 if (active_lh_line < 3)
635 if (exit_client_msg(cptr, LHcptr, &me,
636 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
637 "Leaf-only link %s <- %s(%s), check L:",
639 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
644 ServerStats->is_ref++;
645 if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
649 * Did we kill the incoming server off already ?
659 * Server is informing about a new server behind
660 * this link. Create REMOTE server structure,
661 * add it to list and propagate word to my other
665 acptr = make_client(cptr, STAT_SERVER);
667 acptr->serv->prot = prot;
668 acptr->serv->timestamp = timestamp;
669 acptr->hopcount = hop;
670 ircd_strncpy(acptr->name, host, HOSTLEN);
671 ircd_strncpy(acptr->info, info, REALLEN);
672 acptr->serv->up = sptr;
673 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
674 /* Use cptr, because we do protocol 9 -> 10 translation
675 for numeric nicks ! */
676 SetServerYXX(cptr, acptr, parv[6]);
678 Count_newremoteserver(UserStats);
679 if (Protocol(acptr) < 10)
680 acptr->flags |= FLAGS_TS8;
681 add_client_to_list(acptr);
686 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
687 sptr->name, acptr->name);
691 * Old sendto_serv_but_one() call removed because we now need to send
692 * different names to different servers (domain name matching).
694 * Personally, I think this is bogus; it's a feature we don't use here.
697 for (i = 0; i <= HighestFd; i++)
699 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
700 bcptr == cptr || IsMe(bcptr))
702 if (0 == match(me.name, acptr->name))
704 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
705 acptr->name, hop + 1, parv[4], parv[5], NumServCap(acptr),
711 if (IsUnknown(cptr) || IsHandshake(cptr))
714 cptr->serv->timestamp = timestamp;
715 cptr->serv->prot = prot;
716 cptr->serv->ghost = ghost;
717 SetServerYXX(cptr, cptr, parv[6]);
718 if (start_timestamp > OLDEST_TS)
720 #ifndef RELIABLE_CLOCK
722 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
723 "others start time: %Tu", me.serv->timestamp,
725 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
726 "received timestamp: %Tu ; difference %ld",
727 recv_time, timestamp, timestamp - recv_time);
729 if (start_timestamp < me.serv->timestamp)
731 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
732 "%Tu < %Tu", start_timestamp, me.serv->timestamp);
733 me.serv->timestamp = start_timestamp;
734 TSoffset += timestamp - recv_time;
735 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
736 (int)(timestamp - recv_time));
738 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
739 cptr->serv->timestamp = TStime();
741 else if (timestamp != recv_time)
744 * Equal start times, we have a collision. Let the connected-to server
745 * decide. This assumes leafs issue more than half of the connection
749 cptr->serv->timestamp = TStime();
750 else if (IsHandshake(cptr))
752 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
753 (int)(timestamp - recv_time));
754 TSoffset += timestamp - recv_time;
757 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
758 if (start_timestamp < me.serv->timestamp)
759 me.serv->timestamp = start_timestamp;
761 cptr->serv->timestamp = TStime();
765 ret = server_estab(cptr, aconf, ajupe);
769 #ifdef RELIABLE_CLOCK
770 if (abs(cptr->serv->timestamp - recv_time) > 30)
772 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
773 "timestamp-clock difference of %Td seconds! "
774 "Used SETTIME to correct this.",
775 timestamp - recv_time);
776 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), me.name);
784 * ms_server - server message handler
786 * parv[0] = sender prefix
787 * parv[1] = servername
789 * parv[3] = start timestamp
790 * parv[4] = link timestamp
791 * parv[5] = major protocol version: P09/P10
792 * parv[parc-1] = serverinfo
794 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
795 * numeric nick mask of this server.
796 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
797 * parv[8] = %<lastmod> - optional parameter only present if there's an
798 * outstanding JUPE; specifies the JUPE's lastmod field
800 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
804 char info[REALLEN + 1];
806 struct Client* acptr;
807 struct Client* bcptr;
808 struct Client* LHcptr = 0;
809 struct ConfItem* aconf = 0;
810 struct ConfItem* lhconf = 0;
811 struct Jupe* ajupe = 0;
814 int active_lh_line = 0;
816 time_t start_timestamp;
817 time_t timestamp = 0;
822 if (IsUserPort(cptr))
823 return exit_client_msg(cptr, cptr, &me,
824 "Cannot connect a server to a user port");
826 recv_time = TStime();
830 return need_more_params(sptr, "SERVER");
831 return exit_client(cptr, cptr, &me, "Need more parameters");
838 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
839 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
841 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
844 prot = atoi(parv[5] + 1);
845 if (prot > atoi(MAJOR_PROTOCOL))
846 prot = atoi(MAJOR_PROTOCOL);
848 * Because the previous test is only in 2.10, the following is needed
849 * till all servers are 2.10:
851 if (IsServer(cptr) && prot > Protocol(cptr))
852 prot = Protocol(cptr);
854 start_timestamp = atoi(parv[3]);
855 timestamp = atoi(parv[4]);
856 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
857 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
858 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
860 return exit_client_msg(cptr, sptr, &me,
861 "Bogus timestamps (%s %s)", parv[3], parv[4]);
863 ircd_strncpy(info, parv[parc - 1], REALLEN);
864 info[REALLEN] = '\0';
865 if (prot < atoi(MINOR_PROTOCOL)) {
866 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
867 "(%s) from %s", parv[5], cptr->name);
868 return exit_new_server(cptr, sptr, host, timestamp,
869 "Incompatible protocol: %s", parv[5]);
871 if (parc > 9 && *parv[8] == '%')
872 lastmod = atoi(parv[8] + 1);
873 /* If there's a jupe that matches, and it's a global jupe, and the
874 * introducer didn't indicate it knew of the jupe or has an older
875 * version of the jupe, and the connection isn't in a BURST, resynch
878 if ((ajupe = jupe_find(host)) && !JupeIsLocal(ajupe) &&
879 JupeLastMod(ajupe) > lastmod && !IsBurstOrBurstAck(cptr))
880 jupe_resend(cptr, ajupe);
882 * Check for "FRENCH " infection ;-) (actually this should
883 * be replaced with routine to check the hostname syntax in
884 * general). [ This check is still needed, even after the parse
885 * is fixed, because someone can send "SERVER :foo bar " ].
886 * Also, changed to check other "difficult" characters, now
887 * that parse lets all through... --msa
889 if (strlen(host) > HOSTLEN)
890 host[HOSTLEN] = '\0';
891 for (ch = host; *ch; ch++)
892 if (*ch <= ' ' || *ch > '~')
894 if (*ch || !strchr(host, '.')) {
895 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
897 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
903 * A local server introduces a new server behind this link.
904 * Check if this is allowed according L:, H: and Q: lines.
907 return exit_client_msg(cptr, cptr, &me,
908 "No server info specified for %s", host);
910 * See if the newly found server is behind a guaranteed
911 * leaf (L-line). If so, close the link.
913 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
914 (!lhconf->port || (hop > lhconf->port)))
917 * L: lines normally come in pairs, here we try to
918 * make sure that the oldest link is squitted, not
922 if (timestamp <= cptr->serv->timestamp)
923 LHcptr = 0; /* Kill incoming server */
925 LHcptr = cptr; /* Squit ourselfs */
927 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
928 (lhconf->port && (hop > lhconf->port)))
930 struct Client *ac3ptr;
932 /* Look for net junction causing this: */
933 LHcptr = 0; /* incoming server */
934 if (*parv[5] != 'J') {
935 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
936 if (IsJunction(ac3ptr)) {
945 if (IsUnknown(cptr) || IsHandshake(cptr))
950 * A local link that is still in undefined state wants
951 * to be a SERVER. Check if this is allowed and change
952 * status accordingly...
955 * If there is more then one server on the same machine
956 * that we try to connect to, it could be that the /CONNECT
957 * <mask> caused this connect to be put at the wrong place
958 * in the hashtable. --Run
959 * Same thing for Unknown connections that first send NICK.
961 * Better check if the two strings are (caseless) identical
962 * and not mess with hash internals.
965 if ((!(EmptyString(cptr->name)))
966 && (IsUnknown(cptr) || IsHandshake(cptr))
967 && 0 != ircd_strcmp(cptr->name, host))
968 hChangeClient(cptr, host);
969 ircd_strncpy(cptr->name, host, HOSTLEN);
970 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
971 cptr->hopcount = hop;
973 /* check connection rules */
974 if (0 != conf_eval_crule(host, CRULE_ALL)) {
975 ServerStats->is_ref++;
976 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cptr->name);
977 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
979 if (conf_check_server(cptr)) {
980 ++ServerStats->is_ref;
981 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
982 "from %s.", cptr->name);
983 return exit_client(cptr, cptr, &me, "No C conf lines");
990 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
991 ++ServerStats->is_ref;
993 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
994 "server %s", cptr->name);
995 return exit_client_msg(cptr, cptr, &me,
996 "Access denied. No conf line for server %s", cptr->name);
998 sendto_opmask_butone(0, SNO_OLDSNO, "General C line active: No line "
999 "for server %s", cptr->name);
1001 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1003 sendto_opmask_butone(0, SNO_OLDSNO, "Neither C lines for server %s "
1004 "nor \"general.undernet.org\"", cptr->name);
1005 return exit_client_msg(cptr, cptr, &me,
1006 "No C lines for server %s", cptr->name);
1008 #endif /* GODMODE */
1010 #ifdef CRYPT_LINK_PASSWORD
1011 /* passwd may be NULL. Head it off at the pass... */
1016 salt[0] = aconf->passwd[0];
1017 salt[1] = aconf->passwd[1];
1019 encr = ircd_crypt(cptr->passwd, salt);
1024 encr = cptr->passwd;
1025 #endif /* CRYPT_LINK_PASSWORD */
1027 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1028 ++ServerStats->is_ref;
1029 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
1031 return exit_client_msg(cptr, cptr, &me,
1032 "No Access (passwd mismatch) %s", cptr->name);
1034 #endif /* not GODMODE */
1035 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1038 for (i = 0; i <= HighestFd; i++)
1039 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1048 * We want to find IsConnecting() and IsHandshake() too,
1050 * The second finds collisions with numeric representation of existing
1051 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1054 while ((acptr = FindClient(host)) ||
1055 (parc > 7 && (acptr = FindNServer(parv[6]))))
1058 * This link is trying feed me a server that I already have
1059 * access through another path
1061 * Do not allow Uworld to do this.
1062 * Do not allow servers that are juped.
1063 * Do not allow servers that have older link timestamps
1065 * Do not allow servers that use the same numeric as an existing
1066 * server, but have a different name.
1068 * If my ircd.conf sucks, I can try to connect to myself:
1071 return exit_client_msg(cptr, cptr, &me,
1072 "nick collision with me, check server number in M:? (%s)", host);
1074 * Detect wrong numeric.
1076 if (0 != ircd_strcmp(acptr->name, host))
1078 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1079 ":SERVER Numeric Collision: %s != %s", acptr->name,
1081 return exit_client_msg(cptr, cptr, &me,
1082 "NUMERIC collision between %s and %s."
1083 " Is your server numeric correct ?", host, acptr->name);
1086 * Kill our try, if we had one.
1088 if (IsConnecting(acptr))
1090 if (!active_lh_line && exit_client(cptr, acptr, &me,
1091 "Just connected via another link") == CPTR_KILLED)
1094 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1095 * 'IsServer', because new 'IsConnecting's are refused to
1096 * the same server if we already had it.
1101 * Avoid other nick collisions...
1102 * This is a doubtfull test though, what else would it be
1103 * when it has a server.name ?
1105 else if (!IsServer(acptr) && !IsHandshake(acptr))
1106 return exit_client_msg(cptr, cptr, &me,
1107 "Nickname %s already exists!", host);
1109 * Our new server might be a juped server,
1110 * or someone trying abuse a second Uworld:
1112 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1113 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1115 if (!IsServer(sptr))
1116 return exit_client(cptr, sptr, &me, acptr->info);
1117 sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1118 "from %s !?!", parv[0], parv[1], cptr->name);
1119 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1122 * Of course we find the handshake this link was before :)
1124 else if (IsHandshake(acptr) && acptr == cptr)
1127 * Here we have a server nick collision...
1128 * We don't want to kill the link that was last /connected,
1129 * but we neither want to kill a good (old) link.
1130 * Therefor we kill the second youngest link.
1134 struct Client* c2ptr = 0;
1135 struct Client* c3ptr = acptr;
1136 struct Client* ac2ptr;
1137 struct Client* ac3ptr;
1139 /* Search youngest link: */
1140 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1141 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1145 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1146 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1149 if (timestamp > c3ptr->serv->timestamp)
1152 c2ptr = acptr; /* Make sure they differ */
1154 /* Search second youngest link: */
1155 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1156 if (ac2ptr != c3ptr &&
1157 ac2ptr->serv->timestamp >
1158 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1162 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1163 if (ac2ptr != c3ptr &&
1164 ac2ptr->serv->timestamp >
1165 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1168 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1170 /* If timestamps are equal, decide which link to break
1173 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1174 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1183 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1188 n2up = IsServer(sptr) ? sptr->name : me.name;
1193 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1198 n3up = IsServer(sptr) ? sptr->name : me.name;
1200 if (strcmp(n2, n2up) > 0)
1202 if (strcmp(n3, n3up) > 0)
1204 if (strcmp(n3, n2) > 0)
1211 /* Now squit the second youngest link: */
1213 return exit_new_server(cptr, sptr, host, timestamp,
1214 "server %s already exists and is %ld seconds younger.",
1215 host, (long)acptr->serv->timestamp - (long)timestamp);
1216 else if (c2ptr->from == cptr || IsServer(sptr))
1218 struct Client *killedptrfrom = c2ptr->from;
1222 * If the L: or H: line also gets rid of this link,
1223 * we sent just one squit.
1225 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1228 * If breaking the loop here solves the L: or H:
1229 * line problem, we don't squit that.
1231 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1236 * If we still have a L: or H: line problem,
1237 * we prefer to squit the new server, solving
1238 * loop and L:/H: line problem with only one squit.
1245 * If the new server was introduced by a server that caused a
1246 * Ghost less then 20 seconds ago, this is probably also
1247 * a Ghost... (20 seconds is more then enough because all
1248 * SERVER messages are at the beginning of a net.burst). --Run
1250 if (CurrentTime - cptr->serv->ghost < 20)
1252 killedptrfrom = acptr->from;
1253 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1256 else if (exit_client_msg(cptr, c2ptr, &me,
1257 "Loop <-- %s (new link is %ld seconds younger)", host,
1258 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1259 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1262 * Did we kill the incoming server off already ?
1264 if (killedptrfrom == cptr)
1271 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1273 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1282 * We can't believe it is a lagged server message
1283 * when it directly connects to us...
1284 * kill the older link at the ghost, rather then
1285 * at the second youngest link, assuming it isn't
1288 ghost = CurrentTime; /* Mark that it caused a ghost */
1289 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1299 return exit_new_server(cptr, sptr, host, timestamp,
1300 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1302 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1306 int killed = a_kills_b_too(LHcptr, sptr);
1307 if (active_lh_line < 3)
1309 if (exit_client_msg(cptr, LHcptr, &me,
1310 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1312 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1317 ServerStats->is_ref++;
1318 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1322 * Did we kill the incoming server off already ?
1332 * Server is informing about a new server behind
1333 * this link. Create REMOTE server structure,
1334 * add it to list and propagate word to my other
1338 acptr = make_client(cptr, STAT_SERVER);
1340 acptr->serv->prot = prot;
1341 acptr->serv->timestamp = timestamp;
1342 acptr->hopcount = hop;
1343 ircd_strncpy(acptr->name, host, HOSTLEN);
1344 ircd_strncpy(acptr->info, info, REALLEN);
1345 acptr->serv->up = sptr;
1346 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1347 /* Use cptr, because we do protocol 9 -> 10 translation
1348 for numeric nicks ! */
1349 SetServerYXX(cptr, acptr, parv[6]);
1351 Count_newremoteserver(UserStats);
1352 if (Protocol(acptr) < 10)
1353 acptr->flags |= FLAGS_TS8;
1354 add_client_to_list(acptr);
1356 if (*parv[5] == 'J')
1359 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1360 sptr->name, acptr->name);
1364 * Old sendto_serv_but_one() call removed because we now need to send
1365 * different names to different servers (domain name matching).
1367 for (i = 0; i <= HighestFd; i++)
1369 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1370 bcptr == cptr || IsMe(bcptr))
1372 if (0 == match(me.name, acptr->name))
1374 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1375 acptr->name, hop + 1, parv[4], parv[5], NumServCap(acptr),
1381 if (IsUnknown(cptr) || IsHandshake(cptr))
1384 cptr->serv->timestamp = timestamp;
1385 cptr->serv->prot = prot;
1386 cptr->serv->ghost = ghost;
1387 SetServerYXX(cptr, cptr, parv[6]);
1388 if (start_timestamp > OLDEST_TS)
1390 #ifndef RELIABLE_CLOCK
1392 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
1393 "others start time: %Tu", me.serv->timestamp,
1395 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
1396 "received timestamp: %Tu ; difference %ld",
1397 recv_time, timestamp, timestamp - recv_time);
1399 if (start_timestamp < me.serv->timestamp)
1401 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1402 "%Tu < %Tu", start_timestamp, me.serv->timestamp);
1403 me.serv->timestamp = start_timestamp;
1404 TSoffset += timestamp - recv_time;
1405 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1406 (int)(timestamp - recv_time));
1408 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1409 cptr->serv->timestamp = TStime();
1411 else if (timestamp != recv_time)
1414 * Equal start times, we have a collision. Let the connected-to server
1415 * decide. This assumes leafs issue more than half of the connection
1418 if (IsUnknown(cptr))
1419 cptr->serv->timestamp = TStime();
1420 else if (IsHandshake(cptr))
1422 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1423 (int)(timestamp - recv_time));
1424 TSoffset += timestamp - recv_time;
1427 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
1428 if (start_timestamp < me.serv->timestamp)
1429 me.serv->timestamp = start_timestamp;
1430 if (IsUnknown(cptr))
1431 cptr->serv->timestamp = TStime();
1435 ret = server_estab(cptr, aconf, ajupe);
1439 #ifdef RELIABLE_CLOCK
1440 if (abs(cptr->serv->timestamp - recv_time) > 30)
1442 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1443 "timestamp-clock difference of %Td seconds! Used "
1444 "SETTIME to correct this.", timestamp - recv_time);
1445 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), me.name);
1457 * parv[0] = sender prefix
1458 * parv[1] = servername
1459 * parv[2] = hopcount
1460 * parv[3] = start timestamp
1461 * parv[4] = link timestamp
1462 * parv[5] = major protocol version: P09/P10
1463 * parv[parc-1] = serverinfo
1465 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1466 * numeric nick mask of this server.
1467 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1469 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1473 char info[REALLEN + 1];
1475 struct Client* acptr;
1476 struct Client* bcptr;
1477 struct Client* LHcptr = 0;
1478 struct ConfItem* aconf = 0;
1479 struct ConfItem* lhconf = 0;
1480 struct Jupe* ajupe = 0;
1483 int active_lh_line = 0;
1484 unsigned short prot;
1485 time_t start_timestamp;
1486 time_t timestamp = 0;
1492 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1496 if (IsUserPort(cptr))
1497 return exit_client_msg(cptr, cptr, &me,
1498 "You cannot connect a server to a user port; connect to %s port %u",
1499 me.name, server_port);
1501 recv_time = TStime();
1505 return need_more_params(sptr, "SERVER");
1506 return exit_client(cptr, cptr, &me, "Need more parameters");
1512 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1513 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1515 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1518 prot = atoi(parv[5] + 1);
1519 if (prot > atoi(MAJOR_PROTOCOL))
1520 prot = atoi(MAJOR_PROTOCOL);
1522 * Because the previous test is only in 2.10, the following is needed
1523 * till all servers are 2.10:
1525 if (IsServer(cptr) && prot > Protocol(cptr))
1526 prot = Protocol(cptr);
1527 hop = atoi(parv[2]);
1528 start_timestamp = atoi(parv[3]);
1529 timestamp = atoi(parv[4]);
1530 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1531 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1532 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1534 return exit_client_msg(cptr, sptr, &me,
1535 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1537 ircd_strncpy(info, parv[parc - 1], REALLEN);
1538 info[REALLEN] = '\0';
1539 if (prot < atoi(MINOR_PROTOCOL)) {
1540 sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1541 parv[5], cptr->name);
1542 return exit_new_server(cptr, sptr, host, timestamp,
1543 "Incompatible protocol: %s", parv[5]);
1546 * Check for "FRENCH " infection ;-) (actually this should
1547 * be replaced with routine to check the hostname syntax in
1548 * general). [ This check is still needed, even after the parse
1549 * is fixed, because someone can send "SERVER :foo bar " ].
1550 * Also, changed to check other "difficult" characters, now
1551 * that parse lets all through... --msa
1553 if (strlen(host) > HOSTLEN)
1554 host[HOSTLEN] = '\0';
1555 for (ch = host; *ch; ch++)
1556 if (*ch <= ' ' || *ch > '~')
1558 if (*ch || !strchr(host, '.'))
1560 sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1561 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1567 * A local server introduces a new server behind this link.
1568 * Check if this is allowed according L:, H: and Q: lines.
1570 if (info[0] == '\0')
1571 return exit_client_msg(cptr, cptr, &me,
1572 "No server info specified for %s", host);
1574 * See if the newly found server is behind a guaranteed
1575 * leaf (L-line). If so, close the link.
1577 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1578 (!lhconf->port || (hop > lhconf->port)))
1581 * L: lines normally come in pairs, here we try to
1582 * make sure that the oldest link is squitted, not
1586 if (timestamp <= cptr->serv->timestamp)
1587 LHcptr = 0; /* Kill incoming server */
1589 LHcptr = cptr; /* Squit ourselfs */
1591 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1592 (lhconf->port && (hop > lhconf->port)))
1594 struct Client *ac3ptr;
1596 /* Look for net junction causing this: */
1597 LHcptr = 0; /* incoming server */
1598 if (*parv[5] != 'J') {
1599 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1600 if (IsJunction(ac3ptr)) {
1609 if (IsUnknown(cptr) || IsHandshake(cptr))
1614 * A local link that is still in undefined state wants
1615 * to be a SERVER. Check if this is allowed and change
1616 * status accordingly...
1619 * If there is more then one server on the same machine
1620 * that we try to connect to, it could be that the /CONNECT
1621 * <mask> caused this connect to be put at the wrong place
1622 * in the hashtable. --Run
1623 * Same thing for Unknown connections that first send NICK.
1625 * Better check if the two strings are (caseless) identical
1626 * and not mess with hash internals.
1629 if ((!(EmptyString(cptr->name)))
1630 && (IsUnknown(cptr) || IsHandshake(cptr))
1631 && 0 != ircd_strcmp(cptr->name, host))
1632 hChangeClient(cptr, host);
1633 ircd_strncpy(cptr->name, host, HOSTLEN);
1634 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1635 cptr->hopcount = hop;
1637 /* check connection rules */
1638 if (0 != conf_eval_crule(host, CRULE_ALL)) {
1639 ServerStats->is_ref++;
1640 sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1641 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1643 if (conf_check_server(cptr)) {
1644 ++ServerStats->is_ref;
1645 sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1646 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1653 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1654 ++ServerStats->is_ref;
1656 sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1657 return exit_client_msg(cptr, cptr, &me,
1658 "Access denied. No conf line for server %s", cptr->name);
1660 sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1662 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1664 sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1665 "\"general.undernet.org\"", cptr->name);
1666 return exit_client_msg(cptr, cptr, &me,
1667 "No C/N lines for server %s", cptr->name);
1669 #endif /* GODMODE */
1671 #ifdef CRYPT_LINK_PASSWORD
1672 /* passwd may be NULL. Head it off at the pass... */
1677 salt[0] = aconf->passwd[0];
1678 salt[1] = aconf->passwd[1];
1680 encr = ircd_crypt(cptr->passwd, salt);
1685 encr = cptr->passwd;
1686 #endif /* CRYPT_LINK_PASSWORD */
1688 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1689 ++ServerStats->is_ref;
1690 sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1691 return exit_client_msg(cptr, cptr, &me,
1692 "No Access (passwd mismatch) %s", cptr->name);
1694 #endif /* not GODMODE */
1695 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1698 for (i = 0; i <= HighestFd; i++)
1699 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1708 * We want to find IsConnecting() and IsHandshake() too,
1710 * The second finds collisions with numeric representation of existing
1711 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1714 while ((acptr = FindClient(host)) ||
1715 (parc > 7 && (acptr = FindNServer(parv[6]))))
1718 * This link is trying feed me a server that I already have
1719 * access through another path
1721 * Do not allow Uworld to do this.
1722 * Do not allow servers that are juped.
1723 * Do not allow servers that have older link timestamps
1725 * Do not allow servers that use the same numeric as an existing
1726 * server, but have a different name.
1728 * If my ircd.conf sucks, I can try to connect to myself:
1731 return exit_client_msg(cptr, cptr, &me,
1732 "nick collision with me, check server number in M:? (%s)", host);
1734 * Detect wrong numeric.
1736 if (0 != ircd_strcmp(acptr->name, host))
1738 sendto_serv_butone(cptr, /* XXX DEAD */
1739 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1740 me.name, acptr->name, host);
1741 return exit_client_msg(cptr, cptr, &me,
1742 "NUMERIC collision between %s and %s."
1743 " Is your server numeric correct ?", host, acptr->name);
1746 * Kill our try, if we had one.
1748 if (IsConnecting(acptr))
1750 if (!active_lh_line && exit_client(cptr, acptr, &me,
1751 "Just connected via another link") == CPTR_KILLED)
1754 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1755 * 'IsServer', because new 'IsConnecting's are refused to
1756 * the same server if we already had it.
1761 * Avoid other nick collisions...
1762 * This is a doubtfull test though, what else would it be
1763 * when it has a server.name ?
1765 else if (!IsServer(acptr) && !IsHandshake(acptr))
1766 return exit_client_msg(cptr, cptr, &me,
1767 "Nickname %s already exists!", host);
1769 * Our new server might be a juped server,
1770 * or someone trying abuse a second Uworld:
1772 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1773 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1775 if (!IsServer(sptr))
1776 return exit_client(cptr, sptr, &me, acptr->info);
1777 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1778 me.name, parv[0], parv[1], cptr->name);
1779 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1782 * Of course we find the handshake this link was before :)
1784 else if (IsHandshake(acptr) && acptr == cptr)
1787 * Here we have a server nick collision...
1788 * We don't want to kill the link that was last /connected,
1789 * but we neither want to kill a good (old) link.
1790 * Therefor we kill the second youngest link.
1794 struct Client* c2ptr = 0;
1795 struct Client* c3ptr = acptr;
1796 struct Client* ac2ptr;
1797 struct Client* ac3ptr;
1799 /* Search youngest link: */
1800 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1801 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1805 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1806 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1809 if (timestamp > c3ptr->serv->timestamp)
1812 c2ptr = acptr; /* Make sure they differ */
1814 /* Search second youngest link: */
1815 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1816 if (ac2ptr != c3ptr &&
1817 ac2ptr->serv->timestamp >
1818 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1822 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1823 if (ac2ptr != c3ptr &&
1824 ac2ptr->serv->timestamp >
1825 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1828 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1830 /* If timestamps are equal, decide which link to break
1833 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1834 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1843 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1848 n2up = IsServer(sptr) ? sptr->name : me.name;
1853 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1858 n3up = IsServer(sptr) ? sptr->name : me.name;
1860 if (strcmp(n2, n2up) > 0)
1862 if (strcmp(n3, n3up) > 0)
1864 if (strcmp(n3, n2) > 0)
1871 /* Now squit the second youngest link: */
1873 return exit_new_server(cptr, sptr, host, timestamp,
1874 "server %s already exists and is %ld seconds younger.",
1875 host, (long)acptr->serv->timestamp - (long)timestamp);
1876 else if (c2ptr->from == cptr || IsServer(sptr))
1878 struct Client *killedptrfrom = c2ptr->from;
1882 * If the L: or H: line also gets rid of this link,
1883 * we sent just one squit.
1885 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1888 * If breaking the loop here solves the L: or H:
1889 * line problem, we don't squit that.
1891 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1896 * If we still have a L: or H: line problem,
1897 * we prefer to squit the new server, solving
1898 * loop and L:/H: line problem with only one squit.
1905 * If the new server was introduced by a server that caused a
1906 * Ghost less then 20 seconds ago, this is probably also
1907 * a Ghost... (20 seconds is more then enough because all
1908 * SERVER messages are at the beginning of a net.burst). --Run
1910 if (CurrentTime - cptr->serv->ghost < 20)
1912 killedptrfrom = acptr->from;
1913 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1916 else if (exit_client_msg(cptr, c2ptr, &me,
1917 "Loop <-- %s (new link is %ld seconds younger)", host,
1918 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1919 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1922 * Did we kill the incoming server off already ?
1924 if (killedptrfrom == cptr)
1931 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1933 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1942 * We can't believe it is a lagged server message
1943 * when it directly connects to us...
1944 * kill the older link at the ghost, rather then
1945 * at the second youngest link, assuming it isn't
1948 ghost = CurrentTime; /* Mark that it caused a ghost */
1949 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1959 return exit_new_server(cptr, sptr, host, timestamp,
1960 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1962 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1966 int killed = a_kills_b_too(LHcptr, sptr);
1967 if (active_lh_line < 3)
1969 if (exit_client_msg(cptr, LHcptr, &me,
1970 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1972 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1977 ServerStats->is_ref++;
1978 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1982 * Did we kill the incoming server off already ?
1992 * Server is informing about a new server behind
1993 * this link. Create REMOTE server structure,
1994 * add it to list and propagate word to my other
1998 acptr = make_client(cptr, STAT_SERVER);
2000 acptr->serv->prot = prot;
2001 acptr->serv->timestamp = timestamp;
2002 acptr->hopcount = hop;
2003 ircd_strncpy(acptr->name, host, HOSTLEN);
2004 ircd_strncpy(acptr->info, info, REALLEN);
2005 acptr->serv->up = sptr;
2006 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
2007 /* Use cptr, because we do protocol 9 -> 10 translation
2008 for numeric nicks ! */
2009 SetServerYXX(cptr, acptr, parv[6]);
2011 Count_newremoteserver(UserStats);
2012 if (Protocol(acptr) < 10)
2013 acptr->flags |= FLAGS_TS8;
2014 add_client_to_list(acptr);
2016 if (*parv[5] == 'J')
2019 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
2020 sptr->name, acptr->name);
2024 * Old sendto_serv_but_one() call removed because we now need to send
2025 * different names to different servers (domain name matching).
2027 for (i = 0; i <= HighestFd; i++)
2029 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
2030 bcptr == cptr || IsMe(bcptr))
2032 if (0 == match(me.name, acptr->name))
2034 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
2035 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
2036 NumServCap(acptr), acptr->info);
2041 if (IsUnknown(cptr) || IsHandshake(cptr))
2044 cptr->serv->timestamp = timestamp;
2045 cptr->serv->prot = prot;
2046 cptr->serv->ghost = ghost;
2047 SetServerYXX(cptr, cptr, parv[6]);
2048 if (start_timestamp > OLDEST_TS)
2050 #ifndef RELIABLE_CLOCK
2052 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
2053 TIME_T_FMT, me.serv->timestamp, start_timestamp);
2054 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
2055 TIME_T_FMT " ; difference %ld",
2056 recv_time, timestamp, timestamp - recv_time);
2058 if (start_timestamp < me.serv->timestamp)
2060 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
2061 start_timestamp, me.serv->timestamp);
2062 me.serv->timestamp = start_timestamp;
2063 TSoffset += timestamp - recv_time;
2064 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
2066 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
2067 cptr->serv->timestamp = TStime();
2069 else if (timestamp != recv_time)
2072 * Equal start times, we have a collision. Let the connected-to server
2073 * decide. This assumes leafs issue more than half of the connection
2076 if (IsUnknown(cptr))
2077 cptr->serv->timestamp = TStime();
2078 else if (IsHandshake(cptr))
2080 sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
2081 (int)(timestamp - recv_time));
2082 TSoffset += timestamp - recv_time;
2085 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2086 if (start_timestamp < me.serv->timestamp)
2087 me.serv->timestamp = start_timestamp;
2088 if (IsUnknown(cptr))
2089 cptr->serv->timestamp = TStime();
2093 ret = server_estab(cptr, aconf); /* XXX DEAD */
2097 #ifdef RELIABLE_CLOCK
2098 if (abs(cptr->serv->timestamp - recv_time) > 30)
2100 sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2101 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2102 " this.", timestamp - recv_time);
2103 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2104 me.name, TStime(), me.name);