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 cli_sockhost(cptr), cli_sock_ip(cptr));
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, cli_serv(&me)->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], cli_name(cptr));
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",
225 host, cli_name(cptr));
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(cli_confs(cptr), cli_name(cptr), 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 <= cli_serv(cptr)->timestamp)
252 LHcptr = 0; /* Kill incoming server */
254 LHcptr = cptr; /* Squit ourselfs */
256 else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), 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 = cli_serv(ac3ptr)->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(cli_name(cptr)) &&
295 (IsUnknown(cptr) || IsHandshake(cptr)) &&
296 0 != ircd_strcmp(cli_name(cptr), host))
297 hChangeClient(cptr, host);
298 ircd_strncpy(cli_name(cptr), host, HOSTLEN);
299 ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
300 cli_hopcount(cptr) = 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.", cli_name(cptr));
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.", cli_name(cptr));
313 return exit_client(cptr, cptr, &me, "No C:line");
316 host = cli_name(cptr);
320 if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
321 ++ServerStats->is_ref;
322 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
323 "server %s", cli_name(cptr));
324 return exit_client_msg(cptr, cptr, &me,
325 "Access denied. No conf line for server %s", cli_name(cptr));
327 #ifdef CRYPT_LINK_PASSWORD
328 /* passwd may be NULL. Head it off at the pass... */
329 if (*(cli_passwd(cptr))) {
330 encr = ircd_crypt(cli_passwd(cptr), aconf->passed);
335 encr = cli_passwd(cptr);
336 #endif /* CRYPT_LINK_PASSWORD */
338 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
339 ++ServerStats->is_ref;
340 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
342 return exit_client_msg(cptr, cptr, &me,
343 "No Access (passwd mismatch) %s", cli_name(cptr));
346 memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
349 for (i = 0; i <= HighestFd; i++)
350 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
359 * We want to find IsConnecting() and IsHandshake() too,
361 * The second finds collisions with numeric representation of existing
362 * servers - these shouldn't happen anymore when all upgraded to 2.10.
365 while ((acptr = FindClient(host)) ||
366 (parc > 7 && (acptr = FindNServer(parv[6]))))
369 * This link is trying feed me a server that I already have
370 * access through another path
372 * Do not allow Uworld to do this.
373 * Do not allow servers that are juped.
374 * Do not allow servers that have older link timestamps
376 * Do not allow servers that use the same numeric as an existing
377 * server, but have a different name.
379 * If my ircd.conf sucks, I can try to connect to myself:
382 return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
384 * Detect wrong numeric.
386 if (0 != ircd_strcmp(cli_name(acptr), host)) {
387 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
388 ":SERVER Numeric Collision: %s != %s",
389 cli_name(acptr), host);
390 return exit_client_msg(cptr, cptr, &me,
391 "NUMERIC collision between %s and %s."
392 " Is your server numeric correct ?", host, cli_name(acptr));
395 * Kill our try, if we had one.
397 if (IsConnecting(acptr))
399 if (!active_lh_line && exit_client(cptr, acptr, &me,
400 "Just connected via another link") == CPTR_KILLED)
403 * We can have only ONE 'IsConnecting', 'IsHandshake' or
404 * 'IsServer', because new 'IsConnecting's are refused to
405 * the same server if we already had it.
410 * Avoid other nick collisions...
411 * This is a doubtfull test though, what else would it be
412 * when it has a server.name ?
414 else if (!IsServer(acptr) && !IsHandshake(acptr))
415 return exit_client_msg(cptr, cptr, &me,
416 "Nickname %s already exists!", host);
418 * Our new server might be a juped server,
419 * or someone trying abuse a second Uworld:
421 else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
422 find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
425 return exit_client(cptr, sptr, &me, cli_info(acptr));
426 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
427 ":Received :%s SERVER %s from %s !?!", parv[0],
428 parv[1], cli_name(cptr));
429 return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
432 * Of course we find the handshake this link was before :)
434 else if (IsHandshake(acptr) && acptr == cptr)
437 * Here we have a server nick collision...
438 * We don't want to kill the link that was last /connected,
439 * but we neither want to kill a good (old) link.
440 * Therefor we kill the second youngest link.
444 struct Client* c2ptr = 0;
445 struct Client* c3ptr = acptr;
446 struct Client* ac2ptr;
447 struct Client* ac3ptr;
449 /* Search youngest link: */
450 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
451 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
455 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
456 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
459 if (timestamp > cli_serv(c3ptr)->timestamp)
462 c2ptr = acptr; /* Make sure they differ */
464 /* Search second youngest link: */
465 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
466 if (ac2ptr != c3ptr &&
467 cli_serv(ac2ptr)->timestamp >
468 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
472 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
473 if (ac2ptr != c3ptr &&
474 cli_serv(ac2ptr)->timestamp >
475 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
478 if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
480 /* If timestamps are equal, decide which link to break
483 if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
484 (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
492 n2 = cli_name(c2ptr);
493 n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
498 n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
502 n3 = cli_name(c3ptr);
503 n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
508 n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
510 if (strcmp(n2, n2up) > 0)
512 if (strcmp(n3, n3up) > 0)
514 if (strcmp(n3, n2) > 0)
521 /* Now squit the second youngest link: */
523 return exit_new_server(cptr, sptr, host, timestamp,
524 "server %s already exists and is %ld seconds younger.",
525 host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
526 else if (cli_from(c2ptr) == cptr || IsServer(sptr))
528 struct Client *killedptrfrom = cli_from(c2ptr);
532 * If the L: or H: line also gets rid of this link,
533 * we sent just one squit.
535 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
538 * If breaking the loop here solves the L: or H:
539 * line problem, we don't squit that.
541 if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
546 * If we still have a L: or H: line problem,
547 * we prefer to squit the new server, solving
548 * loop and L:/H: line problem with only one squit.
555 * If the new server was introduced by a server that caused a
556 * Ghost less then 20 seconds ago, this is probably also
557 * a Ghost... (20 seconds is more then enough because all
558 * SERVER messages are at the beginning of a net.burst). --Run
560 if (CurrentTime - cli_serv(cptr)->ghost < 20)
562 killedptrfrom = cli_from(acptr);
563 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
566 else if (exit_client_msg(cptr, c2ptr, &me,
567 "Loop <-- %s (new link is %ld seconds younger)", host,
568 (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
569 (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
572 * Did we kill the incoming server off already ?
574 if (killedptrfrom == cptr)
581 if (LHcptr && a_kills_b_too(LHcptr, acptr))
583 if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
592 * We can't believe it is a lagged server message
593 * when it directly connects to us...
594 * kill the older link at the ghost, rather then
595 * at the second youngest link, assuming it isn't
598 ghost = CurrentTime; /* Mark that it caused a ghost */
599 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
609 return exit_new_server(cptr, sptr, host, timestamp,
610 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
611 "Leaf-only link %s <- %s(%s), check L:",
612 cli_name(cptr), host,
613 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
617 int killed = a_kills_b_too(LHcptr, sptr);
618 if (active_lh_line < 3)
620 if (exit_client_msg(cptr, LHcptr, &me,
621 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s), check H:" :
622 "Leaf-only link %s <- %s(%s), check L:",
623 cli_name(cptr), host,
624 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
629 ServerStats->is_ref++;
630 if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
634 * Did we kill the incoming server off already ?
644 * Server is informing about a new server behind
645 * this link. Create REMOTE server structure,
646 * add it to list and propagate word to my other
650 acptr = make_client(cptr, STAT_SERVER);
652 cli_serv(acptr)->prot = prot;
653 cli_serv(acptr)->timestamp = timestamp;
654 cli_hopcount(acptr) = hop;
655 ircd_strncpy(cli_name(acptr), host, HOSTLEN);
656 ircd_strncpy(cli_info(acptr), info, REALLEN);
657 cli_serv(acptr)->up = sptr;
658 cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
659 /* Use cptr, because we do protocol 9 -> 10 translation
660 for numeric nicks ! */
661 SetServerYXX(cptr, acptr, parv[6]);
663 Count_newremoteserver(UserStats);
664 if (Protocol(acptr) < 10)
665 cli_flags(acptr) |= FLAGS_TS8;
666 add_client_to_list(acptr);
671 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
672 cli_name(sptr), cli_name(acptr));
676 * Old sendto_serv_but_one() call removed because we now need to send
677 * different names to different servers (domain name matching).
679 * Personally, I think this is bogus; it's a feature we don't use here.
682 for (i = 0; i <= HighestFd; i++)
684 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
685 bcptr == cptr || IsMe(bcptr))
687 if (0 == match(cli_name(&me), cli_name(acptr)))
689 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
690 cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
696 if (IsUnknown(cptr) || IsHandshake(cptr))
699 cli_serv(cptr)->timestamp = timestamp;
700 cli_serv(cptr)->prot = prot;
701 cli_serv(cptr)->ghost = ghost;
702 SetServerYXX(cptr, cptr, parv[6]);
703 if (start_timestamp > OLDEST_TS)
705 #ifndef RELIABLE_CLOCK
707 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
708 "others start time: %Tu", cli_serv(&me)->timestamp,
710 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
711 "received timestamp: %Tu ; difference %ld",
712 recv_time, timestamp, timestamp - recv_time);
714 if (start_timestamp < cli_serv(&me)->timestamp)
716 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
717 "%Tu < %Tu", start_timestamp, cli_serv(&me)->timestamp);
718 cli_serv(&me)->timestamp = start_timestamp;
719 TSoffset += timestamp - recv_time;
720 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
721 (int)(timestamp - recv_time));
723 else if ((start_timestamp > cli_serv(&me)->timestamp) && IsUnknown(cptr))
724 cli_serv(cptr)->timestamp = TStime();
726 else if (timestamp != recv_time)
729 * Equal start times, we have a collision. Let the connected-to server
730 * decide. This assumes leafs issue more than half of the connection
734 cli_serv(cptr)->timestamp = TStime();
735 else if (IsHandshake(cptr))
737 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
738 (int)(timestamp - recv_time));
739 TSoffset += timestamp - recv_time;
742 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
743 if (start_timestamp < cli_serv(&me)->timestamp)
744 cli_serv(&me)->timestamp = start_timestamp;
746 cli_serv(cptr)->timestamp = TStime();
750 ret = server_estab(cptr, aconf, ajupe);
754 #ifdef RELIABLE_CLOCK
755 if (abs(cli_serv(cptr)->timestamp - recv_time) > 30)
757 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
758 "timestamp-clock difference of %Td seconds! "
759 "Used SETTIME to correct this.",
760 timestamp - recv_time);
761 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
769 * ms_server - server message handler
771 * parv[0] = sender prefix
772 * parv[1] = servername
774 * parv[3] = start timestamp
775 * parv[4] = link timestamp
776 * parv[5] = major protocol version: P09/P10
777 * parv[parc-1] = serverinfo
779 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
780 * numeric nick mask of this server.
781 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
782 * parv[8] = %<lastmod> - optional parameter only present if there's an
783 * outstanding JUPE; specifies the JUPE's lastmod field
785 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
789 char info[REALLEN + 1];
791 struct Client* acptr;
792 struct Client* bcptr;
793 struct Client* LHcptr = 0;
794 struct ConfItem* aconf = 0;
795 struct ConfItem* lhconf = 0;
796 struct Jupe* ajupe = 0;
799 int active_lh_line = 0;
801 time_t start_timestamp;
802 time_t timestamp = 0;
807 if (IsUserPort(cptr))
808 return exit_client_msg(cptr, cptr, &me,
809 "Cannot connect a server to a user port");
811 recv_time = TStime();
815 return need_more_params(sptr, "SERVER");
816 return exit_client(cptr, cptr, &me, "Need more parameters");
823 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
824 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
826 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
829 prot = atoi(parv[5] + 1);
830 if (prot > atoi(MAJOR_PROTOCOL))
831 prot = atoi(MAJOR_PROTOCOL);
833 * Because the previous test is only in 2.10, the following is needed
834 * till all servers are 2.10:
836 if (IsServer(cptr) && prot > Protocol(cptr))
837 prot = Protocol(cptr);
839 start_timestamp = atoi(parv[3]);
840 timestamp = atoi(parv[4]);
841 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
842 TIME_T_FMT ")", host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
843 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
845 return exit_client_msg(cptr, sptr, &me,
846 "Bogus timestamps (%s %s)", parv[3], parv[4]);
848 ircd_strncpy(info, parv[parc - 1], REALLEN);
849 info[REALLEN] = '\0';
850 if (prot < atoi(MINOR_PROTOCOL)) {
851 sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
852 "(%s) from %s", parv[5], cli_name(cptr));
853 return exit_new_server(cptr, sptr, host, timestamp,
854 "Incompatible protocol: %s", parv[5]);
856 if (parc > 9 && *parv[8] == '%')
857 lastmod = atoi(parv[8] + 1);
858 /* If there's a jupe that matches, and it's a global jupe, and the
859 * introducer didn't indicate it knew of the jupe or has an older
860 * version of the jupe, and the connection isn't in a BURST, resynch
863 if ((ajupe = jupe_find(host)) && !JupeIsLocal(ajupe) &&
864 JupeLastMod(ajupe) > lastmod && !IsBurstOrBurstAck(cptr))
865 jupe_resend(cptr, ajupe);
867 * Check for "FRENCH " infection ;-) (actually this should
868 * be replaced with routine to check the hostname syntax in
869 * general). [ This check is still needed, even after the parse
870 * is fixed, because someone can send "SERVER :foo bar " ].
871 * Also, changed to check other "difficult" characters, now
872 * that parse lets all through... --msa
874 if (strlen(host) > HOSTLEN)
875 host[HOSTLEN] = '\0';
876 for (ch = host; *ch; ch++)
877 if (*ch <= ' ' || *ch > '~')
879 if (*ch || !strchr(host, '.')) {
880 sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
881 host, cli_name(cptr));
882 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
888 * A local server introduces a new server behind this link.
889 * Check if this is allowed according L:, H: and Q: lines.
892 return exit_client_msg(cptr, cptr, &me,
893 "No server info specified for %s", host);
895 * See if the newly found server is behind a guaranteed
896 * leaf (L-line). If so, close the link.
898 if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
899 (!lhconf->port || (hop > lhconf->port)))
902 * L: lines normally come in pairs, here we try to
903 * make sure that the oldest link is squitted, not
907 if (timestamp <= cli_serv(cptr)->timestamp)
908 LHcptr = 0; /* Kill incoming server */
910 LHcptr = cptr; /* Squit ourselfs */
912 else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
913 (lhconf->port && (hop > lhconf->port)))
915 struct Client *ac3ptr;
917 /* Look for net junction causing this: */
918 LHcptr = 0; /* incoming server */
919 if (*parv[5] != 'J') {
920 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
921 if (IsJunction(ac3ptr)) {
930 if (IsUnknown(cptr) || IsHandshake(cptr))
935 * A local link that is still in undefined state wants
936 * to be a SERVER. Check if this is allowed and change
937 * status accordingly...
940 * If there is more then one server on the same machine
941 * that we try to connect to, it could be that the /CONNECT
942 * <mask> caused this connect to be put at the wrong place
943 * in the hashtable. --Run
944 * Same thing for Unknown connections that first send NICK.
946 * Better check if the two strings are (caseless) identical
947 * and not mess with hash internals.
950 if ((!(EmptyString(cli_name(cptr))))
951 && (IsUnknown(cptr) || IsHandshake(cptr))
952 && 0 != ircd_strcmp(cli_name(cptr), host))
953 hChangeClient(cptr, host);
954 ircd_strncpy(cli_name(cptr), host, HOSTLEN);
955 ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
956 cli_hopcount(cptr) = hop;
958 /* check connection rules */
959 if (0 != conf_eval_crule(host, CRULE_ALL)) {
960 ServerStats->is_ref++;
961 sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
962 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
964 if (conf_check_server(cptr)) {
965 ++ServerStats->is_ref;
966 sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
967 "from %s.", cli_name(cptr));
968 return exit_client(cptr, cptr, &me, "No C conf lines");
971 host = cli_name(cptr);
975 if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
976 ++ServerStats->is_ref;
977 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
978 "server %s", cli_name(cptr));
979 return exit_client_msg(cptr, cptr, &me,
980 "Access denied. No conf line for server %s", cli_name(cptr));
982 #ifdef CRYPT_LINK_PASSWORD
983 /* passwd may be NULL. Head it off at the pass... */
984 if (*(cli_passwd(cptr)))
986 encr = ircd_crypt(cli_passwd(cptr), cli_passwd(aconf));
991 encr = cli_passwd(cptr);
992 #endif /* CRYPT_LINK_PASSWORD */
994 if (*(aconf->passwd) && !!strcmp(aconf->passwd, encr)) {
995 ++ServerStats->is_ref;
996 sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
998 return exit_client_msg(cptr, cptr, &me,
999 "No Access (passwd mismatch) %s", cli_name(cptr));
1001 memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
1004 for (i = 0; i <= HighestFd; i++)
1005 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1014 * We want to find IsConnecting() and IsHandshake() too,
1016 * The second finds collisions with numeric representation of existing
1017 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1020 while ((acptr = FindClient(host)) ||
1021 (parc > 7 && (acptr = FindNServer(parv[6]))))
1024 * This link is trying feed me a server that I already have
1025 * access through another path
1027 * Do not allow Uworld to do this.
1028 * Do not allow servers that are juped.
1029 * Do not allow servers that have older link timestamps
1031 * Do not allow servers that use the same numeric as an existing
1032 * server, but have a different name.
1034 * If my ircd.conf sucks, I can try to connect to myself:
1037 return exit_client_msg(cptr, cptr, &me,
1038 "nick collision with me, check server number in M:? (%s)", host);
1040 * Detect wrong numeric.
1042 if (0 != ircd_strcmp(cli_name(acptr), host))
1044 sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1045 ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
1047 return exit_client_msg(cptr, cptr, &me,
1048 "NUMERIC collision between %s and %s."
1049 " Is your server numeric correct ?", host, cli_name(acptr));
1052 * Kill our try, if we had one.
1054 if (IsConnecting(acptr))
1056 if (!active_lh_line && exit_client(cptr, acptr, &me,
1057 "Just connected via another link") == CPTR_KILLED)
1060 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1061 * 'IsServer', because new 'IsConnecting's are refused to
1062 * the same server if we already had it.
1067 * Avoid other nick collisions...
1068 * This is a doubtfull test though, what else would it be
1069 * when it has a server.name ?
1071 else if (!IsServer(acptr) && !IsHandshake(acptr))
1072 return exit_client_msg(cptr, cptr, &me,
1073 "Nickname %s already exists!", host);
1075 * Our new server might be a juped server,
1076 * or someone trying abuse a second Uworld:
1078 else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
1079 find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
1081 if (!IsServer(sptr))
1082 return exit_client(cptr, sptr, &me, cli_info(acptr));
1083 sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1084 "from %s !?!", parv[0], parv[1], cli_name(cptr));
1085 return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
1088 * Of course we find the handshake this link was before :)
1090 else if (IsHandshake(acptr) && acptr == cptr)
1093 * Here we have a server nick collision...
1094 * We don't want to kill the link that was last /connected,
1095 * but we neither want to kill a good (old) link.
1096 * Therefor we kill the second youngest link.
1100 struct Client* c2ptr = 0;
1101 struct Client* c3ptr = acptr;
1102 struct Client* ac2ptr;
1103 struct Client* ac3ptr;
1105 /* Search youngest link: */
1106 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1107 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1111 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1112 if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1115 if (timestamp > cli_serv(c3ptr)->timestamp)
1118 c2ptr = acptr; /* Make sure they differ */
1120 /* Search second youngest link: */
1121 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1122 if (ac2ptr != c3ptr &&
1123 cli_serv(ac2ptr)->timestamp >
1124 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1128 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1129 if (ac2ptr != c3ptr &&
1130 cli_serv(ac2ptr)->timestamp >
1131 (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1134 if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1136 /* If timestamps are equal, decide which link to break
1139 if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
1140 (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
1148 n2 = cli_name(c2ptr);
1149 n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
1154 n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1158 n3 = cli_name(c3ptr);
1159 n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
1164 n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1166 if (strcmp(n2, n2up) > 0)
1168 if (strcmp(n3, n3up) > 0)
1170 if (strcmp(n3, n2) > 0)
1177 /* Now squit the second youngest link: */
1179 return exit_new_server(cptr, sptr, host, timestamp,
1180 "server %s already exists and is %ld seconds younger.",
1181 host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
1182 else if (cli_from(c2ptr) == cptr || IsServer(sptr))
1184 struct Client *killedptrfrom = cli_from(c2ptr);
1188 * If the L: or H: line also gets rid of this link,
1189 * we sent just one squit.
1191 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1194 * If breaking the loop here solves the L: or H:
1195 * line problem, we don't squit that.
1197 if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1202 * If we still have a L: or H: line problem,
1203 * we prefer to squit the new server, solving
1204 * loop and L:/H: line problem with only one squit.
1211 * If the new server was introduced by a server that caused a
1212 * Ghost less then 20 seconds ago, this is probably also
1213 * a Ghost... (20 seconds is more then enough because all
1214 * SERVER messages are at the beginning of a net.burst). --Run
1216 if (CurrentTime - cli_serv(cptr)->ghost < 20)
1218 killedptrfrom = cli_from(acptr);
1219 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1222 else if (exit_client_msg(cptr, c2ptr, &me,
1223 "Loop <-- %s (new link is %ld seconds younger)", host,
1224 (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
1225 (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
1228 * Did we kill the incoming server off already ?
1230 if (killedptrfrom == cptr)
1237 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1239 if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1248 * We can't believe it is a lagged server message
1249 * when it directly connects to us...
1250 * kill the older link at the ghost, rather then
1251 * at the second youngest link, assuming it isn't
1254 ghost = CurrentTime; /* Mark that it caused a ghost */
1255 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1265 return exit_new_server(cptr, sptr, host, timestamp,
1266 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1267 cli_name(cptr), host,
1268 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1272 int killed = a_kills_b_too(LHcptr, sptr);
1273 if (active_lh_line < 3)
1275 if (exit_client_msg(cptr, LHcptr, &me,
1276 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1277 cli_name(cptr), host,
1278 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1283 ServerStats->is_ref++;
1284 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1288 * Did we kill the incoming server off already ?
1298 * Server is informing about a new server behind
1299 * this link. Create REMOTE server structure,
1300 * add it to list and propagate word to my other
1304 acptr = make_client(cptr, STAT_SERVER);
1306 cli_serv(acptr)->prot = prot;
1307 cli_serv(acptr)->timestamp = timestamp;
1308 cli_hopcount(acptr) = hop;
1309 ircd_strncpy(cli_name(acptr), host, HOSTLEN);
1310 ircd_strncpy(cli_info(acptr), info, REALLEN);
1311 cli_serv(acptr)->up = sptr;
1312 cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
1313 /* Use cptr, because we do protocol 9 -> 10 translation
1314 for numeric nicks ! */
1315 SetServerYXX(cptr, acptr, parv[6]);
1317 Count_newremoteserver(UserStats);
1318 if (Protocol(acptr) < 10)
1319 cli_flags(acptr) |= FLAGS_TS8;
1320 add_client_to_list(acptr);
1322 if (*parv[5] == 'J')
1325 sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1326 cli_name(sptr), cli_name(acptr));
1330 * Old sendto_serv_but_one() call removed because we now need to send
1331 * different names to different servers (domain name matching).
1333 for (i = 0; i <= HighestFd; i++)
1335 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1336 bcptr == cptr || IsMe(bcptr))
1338 if (0 == match(cli_name(&me), cli_name(acptr)))
1340 sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1341 cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
1347 if (IsUnknown(cptr) || IsHandshake(cptr))
1350 cli_serv(cptr)->timestamp = timestamp;
1351 cli_serv(cptr)->prot = prot;
1352 cli_serv(cptr)->ghost = ghost;
1353 SetServerYXX(cptr, cptr, parv[6]);
1354 if (start_timestamp > OLDEST_TS)
1356 #ifndef RELIABLE_CLOCK
1358 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: my start time: %Tu ; "
1359 "others start time: %Tu", cli_serv(&me)->timestamp,
1361 sendto_opmask_butone(0, SNO_OLDSNO, "Debug: receive time: %Tu ; "
1362 "received timestamp: %Tu ; difference %ld",
1363 recv_time, timestamp, timestamp - recv_time);
1365 if (start_timestamp < cli_serv(&me)->timestamp)
1367 sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1368 "%Tu < %Tu", start_timestamp, cli_serv(&me)->timestamp);
1369 cli_serv(&me)->timestamp = start_timestamp;
1370 TSoffset += timestamp - recv_time;
1371 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1372 (int)(timestamp - recv_time));
1374 else if ((start_timestamp > cli_serv(&me)->timestamp) && IsUnknown(cptr))
1375 cli_serv(cptr)->timestamp = TStime();
1377 else if (timestamp != recv_time)
1380 * Equal start times, we have a collision. Let the connected-to server
1381 * decide. This assumes leafs issue more than half of the connection
1384 if (IsUnknown(cptr))
1385 cli_serv(cptr)->timestamp = TStime();
1386 else if (IsHandshake(cptr))
1388 sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1389 (int)(timestamp - recv_time));
1390 TSoffset += timestamp - recv_time;
1393 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
1394 if (start_timestamp < cli_serv(&me)->timestamp)
1395 cli_serv(&me)->timestamp = start_timestamp;
1396 if (IsUnknown(cptr))
1397 cli_serv(cptr)->timestamp = TStime();
1401 ret = server_estab(cptr, aconf, ajupe);
1405 #ifdef RELIABLE_CLOCK
1406 if (abs(cli_serv(cptr)->timestamp - recv_time) > 30)
1408 sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1409 "timestamp-clock difference of %Td seconds! Used "
1410 "SETTIME to correct this.", timestamp - recv_time);
1411 sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
1423 * parv[0] = sender prefix
1424 * parv[1] = servername
1425 * parv[2] = hopcount
1426 * parv[3] = start timestamp
1427 * parv[4] = link timestamp
1428 * parv[5] = major protocol version: P09/P10
1429 * parv[parc-1] = serverinfo
1431 * parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1432 * numeric nick mask of this server.
1433 * parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1435 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1439 char info[REALLEN + 1];
1441 struct Client* acptr;
1442 struct Client* bcptr;
1443 struct Client* LHcptr = 0;
1444 struct ConfItem* aconf = 0;
1445 struct ConfItem* lhconf = 0;
1446 struct Jupe* ajupe = 0;
1449 int active_lh_line = 0;
1450 unsigned short prot;
1451 time_t start_timestamp;
1452 time_t timestamp = 0;
1458 sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1462 if (IsUserPort(cptr))
1463 return exit_client_msg(cptr, cptr, &me,
1464 "You cannot connect a server to a user port; connect to %s port %u",
1465 me.name, server_port);
1467 recv_time = TStime();
1471 return need_more_params(sptr, "SERVER");
1472 return exit_client(cptr, cptr, &me, "Need more parameters");
1478 if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1479 return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1481 if (!IsServer(cptr)) /* Don't allow silently connecting a server */
1484 prot = atoi(parv[5] + 1);
1485 if (prot > atoi(MAJOR_PROTOCOL))
1486 prot = atoi(MAJOR_PROTOCOL);
1488 * Because the previous test is only in 2.10, the following is needed
1489 * till all servers are 2.10:
1491 if (IsServer(cptr) && prot > Protocol(cptr))
1492 prot = Protocol(cptr);
1493 hop = atoi(parv[2]);
1494 start_timestamp = atoi(parv[3]);
1495 timestamp = atoi(parv[4]);
1496 Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1497 TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1498 if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1500 return exit_client_msg(cptr, sptr, &me,
1501 "Bogus timestamps (%s %s)", parv[3], parv[4]);
1503 ircd_strncpy(info, parv[parc - 1], REALLEN);
1504 info[REALLEN] = '\0';
1505 if (prot < atoi(MINOR_PROTOCOL)) {
1506 sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1507 parv[5], cptr->name);
1508 return exit_new_server(cptr, sptr, host, timestamp,
1509 "Incompatible protocol: %s", parv[5]);
1512 * Check for "FRENCH " infection ;-) (actually this should
1513 * be replaced with routine to check the hostname syntax in
1514 * general). [ This check is still needed, even after the parse
1515 * is fixed, because someone can send "SERVER :foo bar " ].
1516 * Also, changed to check other "difficult" characters, now
1517 * that parse lets all through... --msa
1519 if (strlen(host) > HOSTLEN)
1520 host[HOSTLEN] = '\0';
1521 for (ch = host; *ch; ch++)
1522 if (*ch <= ' ' || *ch > '~')
1524 if (*ch || !strchr(host, '.'))
1526 sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1527 return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1533 * A local server introduces a new server behind this link.
1534 * Check if this is allowed according L:, H: and Q: lines.
1536 if (info[0] == '\0')
1537 return exit_client_msg(cptr, cptr, &me,
1538 "No server info specified for %s", host);
1540 * See if the newly found server is behind a guaranteed
1541 * leaf (L-line). If so, close the link.
1543 if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1544 (!lhconf->port || (hop > lhconf->port)))
1547 * L: lines normally come in pairs, here we try to
1548 * make sure that the oldest link is squitted, not
1552 if (timestamp <= cptr->serv->timestamp)
1553 LHcptr = 0; /* Kill incoming server */
1555 LHcptr = cptr; /* Squit ourselfs */
1557 else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1558 (lhconf->port && (hop > lhconf->port)))
1560 struct Client *ac3ptr;
1562 /* Look for net junction causing this: */
1563 LHcptr = 0; /* incoming server */
1564 if (*parv[5] != 'J') {
1565 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1566 if (IsJunction(ac3ptr)) {
1575 if (IsUnknown(cptr) || IsHandshake(cptr))
1580 * A local link that is still in undefined state wants
1581 * to be a SERVER. Check if this is allowed and change
1582 * status accordingly...
1585 * If there is more then one server on the same machine
1586 * that we try to connect to, it could be that the /CONNECT
1587 * <mask> caused this connect to be put at the wrong place
1588 * in the hashtable. --Run
1589 * Same thing for Unknown connections that first send NICK.
1591 * Better check if the two strings are (caseless) identical
1592 * and not mess with hash internals.
1595 if ((!(EmptyString(cptr->name)))
1596 && (IsUnknown(cptr) || IsHandshake(cptr))
1597 && 0 != ircd_strcmp(cptr->name, host))
1598 hChangeClient(cptr, host);
1599 ircd_strncpy(cptr->name, host, HOSTLEN);
1600 ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1601 cptr->hopcount = hop;
1603 /* check connection rules */
1604 if (0 != conf_eval_crule(host, CRULE_ALL)) {
1605 ServerStats->is_ref++;
1606 sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1607 return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1609 if (conf_check_server(cptr)) {
1610 ++ServerStats->is_ref;
1611 sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1612 return exit_client(cptr, cptr, &me, "No C/N conf lines");
1619 if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1620 ++ServerStats->is_ref;
1622 sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1623 return exit_client_msg(cptr, cptr, &me,
1624 "Access denied. No conf line for server %s", cptr->name);
1626 sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1628 find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1630 sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1631 "\"general.undernet.org\"", cptr->name);
1632 return exit_client_msg(cptr, cptr, &me,
1633 "No C/N lines for server %s", cptr->name);
1635 #endif /* GODMODE */
1637 #ifdef CRYPT_LINK_PASSWORD
1638 /* passwd may be NULL. Head it off at the pass... */
1641 encr = ircd_crypt(cptr->passwd, aconf->passwd);
1646 encr = cptr->passwd;
1647 #endif /* CRYPT_LINK_PASSWORD */
1649 if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1650 ++ServerStats->is_ref;
1651 sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1652 return exit_client_msg(cptr, cptr, &me,
1653 "No Access (passwd mismatch) %s", cptr->name);
1655 #endif /* not GODMODE */
1656 memset(cptr->passwd, 0, sizeof(cptr->passwd));
1659 for (i = 0; i <= HighestFd; i++)
1660 if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1669 * We want to find IsConnecting() and IsHandshake() too,
1671 * The second finds collisions with numeric representation of existing
1672 * servers - these shouldn't happen anymore when all upgraded to 2.10.
1675 while ((acptr = FindClient(host)) ||
1676 (parc > 7 && (acptr = FindNServer(parv[6]))))
1679 * This link is trying feed me a server that I already have
1680 * access through another path
1682 * Do not allow Uworld to do this.
1683 * Do not allow servers that are juped.
1684 * Do not allow servers that have older link timestamps
1686 * Do not allow servers that use the same numeric as an existing
1687 * server, but have a different name.
1689 * If my ircd.conf sucks, I can try to connect to myself:
1692 return exit_client_msg(cptr, cptr, &me,
1693 "nick collision with me, check server number in M:? (%s)", host);
1695 * Detect wrong numeric.
1697 if (0 != ircd_strcmp(acptr->name, host))
1699 sendto_serv_butone(cptr, /* XXX DEAD */
1700 ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1701 me.name, acptr->name, host);
1702 return exit_client_msg(cptr, cptr, &me,
1703 "NUMERIC collision between %s and %s."
1704 " Is your server numeric correct ?", host, acptr->name);
1707 * Kill our try, if we had one.
1709 if (IsConnecting(acptr))
1711 if (!active_lh_line && exit_client(cptr, acptr, &me,
1712 "Just connected via another link") == CPTR_KILLED)
1715 * We can have only ONE 'IsConnecting', 'IsHandshake' or
1716 * 'IsServer', because new 'IsConnecting's are refused to
1717 * the same server if we already had it.
1722 * Avoid other nick collisions...
1723 * This is a doubtfull test though, what else would it be
1724 * when it has a server.name ?
1726 else if (!IsServer(acptr) && !IsHandshake(acptr))
1727 return exit_client_msg(cptr, cptr, &me,
1728 "Nickname %s already exists!", host);
1730 * Our new server might be a juped server,
1731 * or someone trying abuse a second Uworld:
1733 else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1734 find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1736 if (!IsServer(sptr))
1737 return exit_client(cptr, sptr, &me, acptr->info);
1738 sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1739 me.name, parv[0], parv[1], cptr->name);
1740 return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1743 * Of course we find the handshake this link was before :)
1745 else if (IsHandshake(acptr) && acptr == cptr)
1748 * Here we have a server nick collision...
1749 * We don't want to kill the link that was last /connected,
1750 * but we neither want to kill a good (old) link.
1751 * Therefor we kill the second youngest link.
1755 struct Client* c2ptr = 0;
1756 struct Client* c3ptr = acptr;
1757 struct Client* ac2ptr;
1758 struct Client* ac3ptr;
1760 /* Search youngest link: */
1761 for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1762 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1766 for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1767 if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1770 if (timestamp > c3ptr->serv->timestamp)
1773 c2ptr = acptr; /* Make sure they differ */
1775 /* Search second youngest link: */
1776 for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1777 if (ac2ptr != c3ptr &&
1778 ac2ptr->serv->timestamp >
1779 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1783 for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1784 if (ac2ptr != c3ptr &&
1785 ac2ptr->serv->timestamp >
1786 (c2ptr ? c2ptr->serv->timestamp : timestamp))
1789 if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1791 /* If timestamps are equal, decide which link to break
1794 if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1795 (c3ptr ? c3ptr->serv->timestamp : timestamp))
1804 n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1809 n2up = IsServer(sptr) ? sptr->name : me.name;
1814 n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1819 n3up = IsServer(sptr) ? sptr->name : me.name;
1821 if (strcmp(n2, n2up) > 0)
1823 if (strcmp(n3, n3up) > 0)
1825 if (strcmp(n3, n2) > 0)
1832 /* Now squit the second youngest link: */
1834 return exit_new_server(cptr, sptr, host, timestamp,
1835 "server %s already exists and is %ld seconds younger.",
1836 host, (long)acptr->serv->timestamp - (long)timestamp);
1837 else if (c2ptr->from == cptr || IsServer(sptr))
1839 struct Client *killedptrfrom = c2ptr->from;
1843 * If the L: or H: line also gets rid of this link,
1844 * we sent just one squit.
1846 if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1849 * If breaking the loop here solves the L: or H:
1850 * line problem, we don't squit that.
1852 if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1857 * If we still have a L: or H: line problem,
1858 * we prefer to squit the new server, solving
1859 * loop and L:/H: line problem with only one squit.
1866 * If the new server was introduced by a server that caused a
1867 * Ghost less then 20 seconds ago, this is probably also
1868 * a Ghost... (20 seconds is more then enough because all
1869 * SERVER messages are at the beginning of a net.burst). --Run
1871 if (CurrentTime - cptr->serv->ghost < 20)
1873 killedptrfrom = acptr->from;
1874 if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1877 else if (exit_client_msg(cptr, c2ptr, &me,
1878 "Loop <-- %s (new link is %ld seconds younger)", host,
1879 (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1880 (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1883 * Did we kill the incoming server off already ?
1885 if (killedptrfrom == cptr)
1892 if (LHcptr && a_kills_b_too(LHcptr, acptr))
1894 if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1903 * We can't believe it is a lagged server message
1904 * when it directly connects to us...
1905 * kill the older link at the ghost, rather then
1906 * at the second youngest link, assuming it isn't
1909 ghost = CurrentTime; /* Mark that it caused a ghost */
1910 if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1920 return exit_new_server(cptr, sptr, host, timestamp,
1921 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1923 lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1927 int killed = a_kills_b_too(LHcptr, sptr);
1928 if (active_lh_line < 3)
1930 if (exit_client_msg(cptr, LHcptr, &me,
1931 (active_lh_line == 2) ? "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1933 lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1938 ServerStats->is_ref++;
1939 if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1943 * Did we kill the incoming server off already ?
1953 * Server is informing about a new server behind
1954 * this link. Create REMOTE server structure,
1955 * add it to list and propagate word to my other
1959 acptr = make_client(cptr, STAT_SERVER);
1961 acptr->serv->prot = prot;
1962 acptr->serv->timestamp = timestamp;
1963 acptr->hopcount = hop;
1964 ircd_strncpy(acptr->name, host, HOSTLEN);
1965 ircd_strncpy(acptr->info, info, REALLEN);
1966 acptr->serv->up = sptr;
1967 acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1968 /* Use cptr, because we do protocol 9 -> 10 translation
1969 for numeric nicks ! */
1970 SetServerYXX(cptr, acptr, parv[6]);
1972 Count_newremoteserver(UserStats);
1973 if (Protocol(acptr) < 10)
1974 acptr->flags |= FLAGS_TS8;
1975 add_client_to_list(acptr);
1977 if (*parv[5] == 'J')
1980 sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
1981 sptr->name, acptr->name);
1985 * Old sendto_serv_but_one() call removed because we now need to send
1986 * different names to different servers (domain name matching).
1988 for (i = 0; i <= HighestFd; i++)
1990 if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1991 bcptr == cptr || IsMe(bcptr))
1993 if (0 == match(me.name, acptr->name))
1995 sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
1996 NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1997 NumServCap(acptr), acptr->info);
2002 if (IsUnknown(cptr) || IsHandshake(cptr))
2005 cptr->serv->timestamp = timestamp;
2006 cptr->serv->prot = prot;
2007 cptr->serv->ghost = ghost;
2008 SetServerYXX(cptr, cptr, parv[6]);
2009 if (start_timestamp > OLDEST_TS)
2011 #ifndef RELIABLE_CLOCK
2013 sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
2014 TIME_T_FMT, me.serv->timestamp, start_timestamp);
2015 sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
2016 TIME_T_FMT " ; difference %ld",
2017 recv_time, timestamp, timestamp - recv_time);
2019 if (start_timestamp < me.serv->timestamp)
2021 sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
2022 start_timestamp, me.serv->timestamp);
2023 me.serv->timestamp = start_timestamp;
2024 TSoffset += timestamp - recv_time;
2025 sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
2027 else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
2028 cptr->serv->timestamp = TStime();
2030 else if (timestamp != recv_time)
2033 * Equal start times, we have a collision. Let the connected-to server
2034 * decide. This assumes leafs issue more than half of the connection
2037 if (IsUnknown(cptr))
2038 cptr->serv->timestamp = TStime();
2039 else if (IsHandshake(cptr))
2041 sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
2042 (int)(timestamp - recv_time));
2043 TSoffset += timestamp - recv_time;
2046 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2047 if (start_timestamp < me.serv->timestamp)
2048 me.serv->timestamp = start_timestamp;
2049 if (IsUnknown(cptr))
2050 cptr->serv->timestamp = TStime();
2054 ret = server_estab(cptr, aconf); /* XXX DEAD */
2058 #ifdef RELIABLE_CLOCK
2059 if (abs(cptr->serv->timestamp - recv_time) > 30)
2061 sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2062 " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2063 " this.", timestamp - recv_time);
2064 sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2065 me.name, TStime(), me.name);