]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/m_server.c
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.
24 * @brief Handlers for the SERVER command.
25 * @version $Id: m_server.c,v 1.41 2005/05/30 16:51:05 entrope Exp $
34 #include "ircd_features.h"
35 #include "ircd_reply.h"
36 #include "ircd_string.h"
43 #include "querycmds.h"
52 /* #include <assert.h> -- Now using assert in ircd_log.h */
56 /** Clean up a server name.
57 * @param[in] host Input server name.
58 * @return NULL if the name is invalid, else pointer to cleaned-up name.
61 clean_servername(char *host
)
65 * Check for "FRENCH " infection ;-) (actually this should
66 * be replaced with routine to check the hostname syntax in
67 * general). [ This check is still needed, even after the parse
68 * is fixed, because someone can send "SERVER :foo bar " ].
69 * Also, changed to check other "difficult" characters, now
70 * that parse lets all through... --msa
72 if (strlen(host
) > HOSTLEN
)
75 for (ch
= host
; *ch
; ch
++)
76 if (*ch
<= ' ' || *ch
> '~')
78 if (*ch
|| !strchr(host
, '.') || strlen(host
) > HOSTLEN
)
83 /** Parse protocol version from a string.
84 * @param[in] proto String version of protocol number.
85 * @return Zero if \a proto is unrecognized, else protocol version.
88 parse_protocol(const char *proto
)
91 if (strlen(proto
) != 3 || (proto
[0] != 'P' && proto
[0] != 'J'))
94 if (prot
> atoi(MAJOR_PROTOCOL
))
95 prot
= atoi(MAJOR_PROTOCOL
);
99 /** Check whether the introduction of a new server would cause a loop
100 * or be disallowed by leaf and hub configuration directives.
101 * @param[in] cptr Neighbor who sent the message.
102 * @param[in] sptr Client that originated the message.
103 * @param[out] ghost If non-NULL, receives ghost timestamp for new server.
104 * @param[in] host Name of new server.
105 * @param[in] numnick Numnick mask of new server.
106 * @param[in] timestamp Claimed link timestamp of new server.
107 * @param[in] hop Number of hops to the new server.
108 * @param[in] junction Non-zero if the new server is still bursting.
109 * @return CPTR_KILLED if \a cptr was SQUIT. 0 if some other server
110 * was SQUIT. 1 if the new server is allowed.
113 check_loop_and_lh(struct Client
* cptr
, struct Client
*sptr
, time_t *ghost
, const char *host
, const char *numnick
, time_t timestamp
, int hop
, int junction
)
115 struct Client
* acptr
;
116 struct Client
* LHcptr
= NULL
;
117 struct ConfItem
* lhconf
;
118 int active_lh_line
= 0, ii
;
124 * Calculate type of connect limit and applicable config item.
126 lhconf
= find_conf_byname(cli_confs(cptr
), cli_name(cptr
), CONF_SERVER
);
127 assert(lhconf
!= NULL
);
130 if (!feature_bool(FEAT_HUB
))
131 for (ii
= 0; ii
<= HighestFd
; ii
++)
132 if (LocalClientArray
[ii
] && IsServer(LocalClientArray
[ii
])) {
137 else if (hop
> lhconf
->maximum
)
141 else if (lhconf
->hub_limit
&& match(lhconf
->hub_limit
, host
))
143 struct Client
*ac3ptr
;
146 for (ac3ptr
= sptr
; ac3ptr
!= &me
; ac3ptr
= cli_serv(ac3ptr
)->up
)
147 if (IsJunction(ac3ptr
)) {
154 * We want to find IsConnecting() and IsHandshake() too,
156 * The second finds collisions with numeric representation of existing
157 * servers - these shouldn't happen anymore when all upgraded to 2.10.
160 while ((acptr
= FindClient(host
))
161 || (numnick
&& (acptr
= FindNServer(numnick
))))
164 * This link is trying feed me a server that I already have
165 * access through another path
167 * Do not allow Uworld to do this.
168 * Do not allow servers that are juped.
169 * Do not allow servers that have older link timestamps
171 * Do not allow servers that use the same numeric as an existing
172 * server, but have a different name.
174 * If my ircd.conf sucks, I can try to connect to myself:
177 return exit_client_msg(cptr
, cptr
, &me
, "nick collision with me (%s), check server number in M:?", host
);
179 * Detect wrong numeric.
181 if (0 != ircd_strcmp(cli_name(acptr
), host
))
183 sendcmdto_serv_butone(&me
, CMD_WALLOPS
, cptr
,
184 ":SERVER Numeric Collision: %s != %s",
185 cli_name(acptr
), host
);
186 return exit_client_msg(cptr
, cptr
, &me
,
187 "NUMERIC collision between %s and %s."
188 " Is your server numeric correct ?", host
, cli_name(acptr
));
191 * Kill our try, if we had one.
193 if (IsConnecting(acptr
))
195 if (!active_lh_line
&& exit_client(cptr
, acptr
, &me
,
196 "Just connected via another link") == CPTR_KILLED
)
199 * We can have only ONE 'IsConnecting', 'IsHandshake' or
200 * 'IsServer', because new 'IsConnecting's are refused to
201 * the same server if we already had it.
206 * Avoid other nick collisions...
207 * This is a doubtful test though, what else would it be
208 * when it has a server.name ?
210 else if (!IsServer(acptr
) && !IsHandshake(acptr
))
211 return exit_client_msg(cptr
, cptr
, &me
,
212 "Nickname %s already exists!", host
);
214 * Our new server might be a juped server,
215 * or someone trying abuse a second Uworld:
217 else if (IsServer(acptr
) && (0 == ircd_strncmp(cli_info(acptr
), "JUPE", 4) ||
218 find_conf_byhost(cli_confs(cptr
), cli_name(acptr
), CONF_UWORLD
)))
221 return exit_client(cptr
, sptr
, &me
, cli_info(acptr
));
222 sendcmdto_serv_butone(&me
, CMD_WALLOPS
, cptr
,
223 ":Received :%s SERVER %s from %s !?!",
224 NumServ(cptr
), host
, cli_name(cptr
));
225 return exit_new_server(cptr
, sptr
, host
, timestamp
, "%s", cli_info(acptr
));
228 * Of course we find the handshake this link was before :)
230 else if (IsHandshake(acptr
) && acptr
== cptr
)
233 * Here we have a server nick collision...
234 * We don't want to kill the link that was last /connected,
235 * but we neither want to kill a good (old) link.
236 * Therefor we kill the second youngest link.
240 struct Client
* c2ptr
= 0;
241 struct Client
* c3ptr
= acptr
;
242 struct Client
* ac2ptr
;
243 struct Client
* ac3ptr
;
245 /* Search youngest link: */
246 for (ac3ptr
= acptr
; ac3ptr
!= &me
; ac3ptr
= cli_serv(ac3ptr
)->up
)
247 if (cli_serv(ac3ptr
)->timestamp
> cli_serv(c3ptr
)->timestamp
)
251 for (ac3ptr
= sptr
; ac3ptr
!= &me
; ac3ptr
= cli_serv(ac3ptr
)->up
)
252 if (cli_serv(ac3ptr
)->timestamp
> cli_serv(c3ptr
)->timestamp
)
255 if (timestamp
> cli_serv(c3ptr
)->timestamp
)
258 c2ptr
= acptr
; /* Make sure they differ */
260 /* Search second youngest link: */
261 for (ac2ptr
= acptr
; ac2ptr
!= &me
; ac2ptr
= cli_serv(ac2ptr
)->up
)
262 if (ac2ptr
!= c3ptr
&&
263 cli_serv(ac2ptr
)->timestamp
>
264 (c2ptr
? cli_serv(c2ptr
)->timestamp
: timestamp
))
268 for (ac2ptr
= sptr
; ac2ptr
!= &me
; ac2ptr
= cli_serv(ac2ptr
)->up
)
269 if (ac2ptr
!= c3ptr
&&
270 cli_serv(ac2ptr
)->timestamp
>
271 (c2ptr
? cli_serv(c2ptr
)->timestamp
: timestamp
))
274 if (c3ptr
&& timestamp
> (c2ptr
? cli_serv(c2ptr
)->timestamp
: timestamp
))
276 /* If timestamps are equal, decide which link to break
279 if ((c2ptr
? cli_serv(c2ptr
)->timestamp
: timestamp
) ==
280 (c3ptr
? cli_serv(c3ptr
)->timestamp
: timestamp
))
282 const char *n2
, *n2up
, *n3
, *n3up
;
285 n2
= cli_name(c2ptr
);
286 n2up
= MyConnect(c2ptr
) ? cli_name(&me
) : cli_name(cli_serv(c2ptr
)->up
);
291 n2up
= IsServer(sptr
) ? cli_name(sptr
) : cli_name(&me
);
295 n3
= cli_name(c3ptr
);
296 n3up
= MyConnect(c3ptr
) ? cli_name(&me
) : cli_name(cli_serv(c3ptr
)->up
);
301 n3up
= IsServer(sptr
) ? cli_name(sptr
) : cli_name(&me
);
303 if (strcmp(n2
, n2up
) > 0)
305 if (strcmp(n3
, n3up
) > 0)
307 if (strcmp(n3
, n2
) > 0)
314 /* Now squit the second youngest link: */
316 return exit_new_server(cptr
, sptr
, host
, timestamp
,
317 "server %s already exists and is %ld seconds younger.",
318 host
, (long)cli_serv(acptr
)->timestamp
- (long)timestamp
);
319 else if (cli_from(c2ptr
) == cptr
|| IsServer(sptr
))
321 struct Client
*killedptrfrom
= cli_from(c2ptr
);
325 * If the L: or H: line also gets rid of this link,
326 * we sent just one squit.
328 if (LHcptr
&& a_kills_b_too(LHcptr
, c2ptr
))
331 * If breaking the loop here solves the L: or H:
332 * line problem, we don't squit that.
334 if (cli_from(c2ptr
) == cptr
|| (LHcptr
&& a_kills_b_too(c2ptr
, LHcptr
)))
339 * If we still have a L: or H: line problem,
340 * we prefer to squit the new server, solving
341 * loop and L:/H: line problem with only one squit.
348 * If the new server was introduced by a server that caused a
349 * Ghost less then 20 seconds ago, this is probably also
350 * a Ghost... (20 seconds is more then enough because all
351 * SERVER messages are at the beginning of a net.burst). --Run
353 if (CurrentTime
- cli_serv(cptr
)->ghost
< 20)
355 killedptrfrom
= cli_from(acptr
);
356 if (exit_client(cptr
, acptr
, &me
, "Ghost loop") == CPTR_KILLED
)
359 else if (exit_client_msg(cptr
, c2ptr
, &me
,
360 "Loop <-- %s (new link is %ld seconds younger)", host
,
361 (c3ptr
? (long)cli_serv(c3ptr
)->timestamp
: timestamp
) -
362 (long)cli_serv(c2ptr
)->timestamp
) == CPTR_KILLED
)
365 * Did we kill the incoming server off already ?
367 if (killedptrfrom
== cptr
)
374 if (LHcptr
&& a_kills_b_too(LHcptr
, acptr
))
376 if (cli_from(acptr
) == cptr
|| (LHcptr
&& a_kills_b_too(acptr
, LHcptr
)))
385 * We can't believe it is a lagged server message
386 * when it directly connects to us...
387 * kill the older link at the ghost, rather then
388 * at the second youngest link, assuming it isn't
392 *ghost
= CurrentTime
; /* Mark that it caused a ghost */
393 if (exit_client(cptr
, acptr
, &me
, "Ghost") == CPTR_KILLED
)
404 killed
= a_kills_b_too(LHcptr
, sptr
);
407 if (active_lh_line
== 1)
409 if (exit_client_msg(cptr
, LHcptr
, &me
,
410 "Leaf-only link %s <- %s, check L:",
411 cli_name(cptr
), host
) == CPTR_KILLED
)
414 else if (active_lh_line
== 2)
416 if (exit_client_msg(cptr
, LHcptr
, &me
,
417 "Non-Hub link %s <- %s, check H:",
418 cli_name(cptr
), host
) == CPTR_KILLED
)
423 ServerStats
->is_ref
++;
424 if (exit_client(cptr
, LHcptr
, &me
, "I'm a leaf, define HUB") == CPTR_KILLED
)
428 * Did we kill the incoming server off already ?
437 /** Update server start timestamps and TS offsets.
438 * @param[in] cptr Server that just connected.
439 * @param[in] timestamp Current time according to \a cptr.
440 * @param[in] start_timestamp Time that \a cptr started.
441 * @param[in] recv_time Current time as we know it.
444 check_start_timestamp(struct Client
*cptr
, time_t timestamp
, time_t start_timestamp
, time_t recv_time
)
446 Debug((DEBUG_DEBUG
, "My start time: %Tu; other's start time: %Tu",
447 cli_serv(&me
)->timestamp
, start_timestamp
));
448 Debug((DEBUG_DEBUG
, "Receive time: %Tu; received timestamp: %Tu; "
449 "difference %ld", recv_time
, timestamp
, timestamp
- recv_time
));
450 if (feature_bool(FEAT_RELIABLE_CLOCK
)) {
451 if (start_timestamp
< cli_serv(&me
)->timestamp
)
452 cli_serv(&me
)->timestamp
= start_timestamp
;
454 cli_serv(cptr
)->timestamp
= TStime();
455 } else if (start_timestamp
< cli_serv(&me
)->timestamp
) {
456 sendto_opmask_butone(0, SNO_OLDSNO
, "got earlier start time: "
457 "%Tu < %Tu", start_timestamp
,
458 cli_serv(&me
)->timestamp
);
459 cli_serv(&me
)->timestamp
= start_timestamp
;
460 TSoffset
+= timestamp
- recv_time
;
461 sendto_opmask_butone(0, SNO_OLDSNO
, "clock adjusted by adding %d",
462 (int)(timestamp
- recv_time
));
463 } else if ((start_timestamp
> cli_serv(&me
)->timestamp
) &&
465 cli_serv(cptr
)->timestamp
= TStime();
466 } else if (timestamp
!= recv_time
) {
468 * Equal start times, we have a collision. Let the connected-to
469 * server decide. This assumes leafs issue more than half of the
470 * connection attempts.
473 cli_serv(cptr
)->timestamp
= TStime();
474 else if (IsHandshake(cptr
)) {
475 sendto_opmask_butone(0, SNO_OLDSNO
, "clock adjusted by adding %d",
476 (int)(timestamp
- recv_time
));
477 TSoffset
+= timestamp
- recv_time
;
482 /** Interpret a server's flags.
484 * @param[in] cptr New server structure.
485 * @param[in] flags String listing server's P10 flags.
487 void set_server_flags(struct Client
*cptr
, const char *flags
)
489 while (*flags
) switch (*flags
++) {
490 case 'h': SetHub(cptr
); break;
491 case 's': SetService(cptr
); break;
492 case '6': SetIPv6(cptr
); break;
496 /** Handle a SERVER message from an unregistered connection.
498 * \a parv has the following elements:
499 * \li \a parv[1] is the server name
500 * \li \a parv[2] is the hop count to the server
501 * \li \a parv[3] is the start timestamp for the server
502 * \li \a parv[4] is the link timestamp
503 * \li \a parv[5] is the protocol version (P10 or J10)
504 * \li \a parv[6] is the numnick mask for the server
505 * \li \a parv[7] is a string of flags like +hs to mark hubs and services
506 * \li \a parv[\a parc - 1] is the server description
508 * See @ref m_functions for discussion of the arguments.
509 * @param[in] cptr Client that sent us the message.
510 * @param[in] sptr Original source of message.
511 * @param[in] parc Number of arguments.
512 * @param[in] parv Argument vector.
514 int mr_server(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
517 struct ConfItem
* aconf
;
522 time_t start_timestamp
;
527 if (IsUserPort(cptr
))
528 return exit_client_msg(cptr
, cptr
, &me
,
529 "Cannot connect a server to a user port");
533 need_more_params(sptr
, "SERVER");
534 return exit_client(cptr
, cptr
, &me
, "Need more parameters");
536 host
= clean_servername(parv
[1]);
539 sendto_opmask_butone(0, SNO_OLDSNO
, "Bogus server name (%s) from %s",
540 host
, cli_name(cptr
));
541 return exit_client_msg(cptr
, cptr
, &me
, "Bogus server name (%s)", host
);
544 if ((ajupe
= jupe_find(host
)) && JupeIsActive(ajupe
))
545 return exit_client_msg(cptr
, sptr
, &me
, "Juped: %s", JupeReason(ajupe
));
547 /* check connection rules */
548 if (0 != conf_eval_crule(host
, CRULE_ALL
)) {
549 ServerStats
->is_ref
++;
550 sendto_opmask_butone(0, SNO_OLDSNO
, "Refused connection from %s.", cli_name(cptr
));
551 return exit_client(cptr
, cptr
, &me
, "Disallowed by connection rule");
554 log_write(LS_NETWORK
, L_NOTICE
, LOG_NOSNOTICE
, "SERVER: %s %s[%s]", host
,
555 cli_sockhost(cptr
), cli_sock_ip(cptr
));
561 start_timestamp
= atoi(parv
[3]);
562 timestamp
= atoi(parv
[4]);
563 prot
= parse_protocol(parv
[5]);
565 return exit_client_msg(cptr
, sptr
, &me
, "Bogus protocol (%s)", parv
[5]);
566 else if (prot
< atoi(MINOR_PROTOCOL
))
567 return exit_new_server(cptr
, sptr
, host
, timestamp
,
568 "Incompatible protocol: %s", parv
[5]);
570 Debug((DEBUG_INFO
, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
571 host
, parv
[4], start_timestamp
, cli_serv(&me
)->timestamp
));
573 if (timestamp
< OLDEST_TS
|| start_timestamp
< OLDEST_TS
)
574 return exit_client_msg(cptr
, sptr
, &me
,
575 "Bogus timestamps (%s %s)", parv
[3], parv
[4]);
577 /* If the server had a different name before, change it. */
578 if (!EmptyString(cli_name(cptr
)) &&
579 (IsUnknown(cptr
) || IsHandshake(cptr
)) &&
580 0 != ircd_strcmp(cli_name(cptr
), host
))
581 hChangeClient(cptr
, host
);
582 ircd_strncpy(cli_name(cptr
), host
, HOSTLEN
);
583 ircd_strncpy(cli_info(cptr
), parv
[parc
-1][0] ? parv
[parc
-1] : cli_name(&me
), REALLEN
);
584 cli_hopcount(cptr
) = hop
;
586 if (conf_check_server(cptr
)) {
587 ++ServerStats
->is_ref
;
588 sendto_opmask_butone(0, SNO_OLDSNO
, "Received unauthorized connection "
589 "from %s.", cli_name(cptr
));
590 log_write(LS_NETWORK
, L_NOTICE
, LOG_NOSNOTICE
, "Received unauthorized "
591 "connection from %C [%s]", cptr
,
592 ircd_ntoa(&cli_ip(cptr
)));
593 return exit_client(cptr
, cptr
, &me
, "No Connect block");
596 host
= cli_name(cptr
);
600 if (!(aconf
= find_conf_byname(cli_confs(cptr
), host
, CONF_SERVER
))) {
601 ++ServerStats
->is_ref
;
602 sendto_opmask_butone(0, SNO_OLDSNO
, "Access denied. No conf line for "
603 "server %s", cli_name(cptr
));
604 return exit_client_msg(cptr
, cptr
, &me
,
605 "Access denied. No conf line for server %s", cli_name(cptr
));
608 if (*aconf
->passwd
&& !!strcmp(aconf
->passwd
, cli_passwd(cptr
))) {
609 ++ServerStats
->is_ref
;
610 sendto_opmask_butone(0, SNO_OLDSNO
, "Access denied (passwd mismatch) %s",
612 return exit_client_msg(cptr
, cptr
, &me
,
613 "No Access (passwd mismatch) %s", cli_name(cptr
));
616 memset(cli_passwd(cptr
), 0, sizeof(cli_passwd(cptr
)));
618 ret
= check_loop_and_lh(cptr
, sptr
, &ghost
, host
, (parc
> 7 ? parv
[6] : NULL
), timestamp
, hop
, 1);
623 cli_serv(cptr
)->timestamp
= timestamp
;
624 cli_serv(cptr
)->prot
= prot
;
625 cli_serv(cptr
)->ghost
= ghost
;
626 memset(cli_privs(cptr
), 255, sizeof(struct Privs
));
627 ClrPriv(cptr
, PRIV_SET
);
628 SetServerYXX(cptr
, cptr
, parv
[6]);
630 /* Attach any necessary UWorld config items. */
631 attach_confs_byhost(cptr
, host
, CONF_UWORLD
);
634 set_server_flags(cptr
, parv
[7] + 1);
636 recv_time
= TStime();
637 check_start_timestamp(cptr
, timestamp
, start_timestamp
, recv_time
);
638 ret
= server_estab(cptr
, aconf
);
640 if (feature_bool(FEAT_RELIABLE_CLOCK
) &&
641 abs(cli_serv(cptr
)->timestamp
- recv_time
) > 30) {
642 sendto_opmask_butone(0, SNO_OLDSNO
, "Connected to a net with a "
643 "timestamp-clock difference of %Td seconds! "
644 "Used SETTIME to correct this.",
645 timestamp
- recv_time
);
646 sendcmdto_prio_one(&me
, CMD_SETTIME
, cptr
, "%Tu :%s", TStime(),
653 /** Handle a SERVER message from another server.
655 * \a parv has the following elements:
656 * \li \a parv[1] is the server name
657 * \li \a parv[2] is the hop count to the server
658 * \li \a parv[3] is the start timestamp for the server
659 * \li \a parv[4] is the link timestamp
660 * \li \a parv[5] is the protocol version (P10 or J10)
661 * \li \a parv[6] is the numnick mask for the server
662 * \li \a parv[7] is a string of flags like +hs to mark hubs and services
663 * \li \a parv[\a parc - 1] is the server description
665 * See @ref m_functions for discussion of the arguments.
666 * @param[in] cptr Client that sent us the message.
667 * @param[in] sptr Original source of message.
668 * @param[in] parc Number of arguments.
669 * @param[in] parv Argument vector.
671 int ms_server(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
675 struct Client
* acptr
;
676 struct Client
* bcptr
;
680 time_t start_timestamp
;
685 return need_more_params(sptr
, "SERVER");
686 return exit_client(cptr
, cptr
, &me
, "Need more parameters");
688 host
= clean_servername(parv
[1]);
691 sendto_opmask_butone(0, SNO_OLDSNO
, "Bogus server name (%s) from %s",
692 host
, cli_name(cptr
));
693 return exit_client_msg(cptr
, cptr
, &me
, "Bogus server name (%s)", host
);
700 start_timestamp
= atoi(parv
[3]);
701 timestamp
= atoi(parv
[4]);
702 prot
= parse_protocol(parv
[5]);
704 return exit_client_msg(cptr
, sptr
, &me
, "Bogus protocol (%s)", parv
[5]);
705 else if (prot
< atoi(MINOR_PROTOCOL
))
706 return exit_new_server(cptr
, sptr
, host
, timestamp
,
707 "Incompatible protocol: %s", parv
[5]);
709 Debug((DEBUG_INFO
, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
710 host
, parv
[4], start_timestamp
, cli_serv(&me
)->timestamp
));
712 if (timestamp
< OLDEST_TS
)
713 return exit_client_msg(cptr
, sptr
, &me
,
714 "Bogus timestamps (%s %s)", parv
[3], parv
[4]);
716 if (parv
[parc
- 1][0] == '\0')
717 return exit_client_msg(cptr
, cptr
, &me
,
718 "No server info specified for %s", host
);
720 ret
= check_loop_and_lh(cptr
, sptr
, NULL
, host
, (parc
> 7 ? parv
[6] : NULL
), timestamp
, hop
, parv
[5][0] == 'J');
725 * Server is informing about a new server behind
726 * this link. Create REMOTE server structure,
727 * add it to list and propagate word to my other
731 acptr
= make_client(cptr
, STAT_SERVER
);
733 cli_serv(acptr
)->prot
= prot
;
734 cli_serv(acptr
)->timestamp
= timestamp
;
735 cli_hopcount(acptr
) = hop
;
736 ircd_strncpy(cli_name(acptr
), host
, HOSTLEN
);
737 ircd_strncpy(cli_info(acptr
), parv
[parc
-1], REALLEN
);
738 cli_serv(acptr
)->up
= sptr
;
739 cli_serv(acptr
)->updown
= add_dlink(&(cli_serv(sptr
))->down
, acptr
);
740 /* Use cptr, because we do protocol 9 -> 10 translation
741 for numeric nicks ! */
742 SetServerYXX(cptr
, acptr
, parv
[6]);
744 /* Attach any necessary UWorld config items. */
745 attach_confs_byhost(cptr
, host
, CONF_UWORLD
);
748 set_server_flags(acptr
, parv
[7] + 1);
750 Count_newremoteserver(UserStats
);
751 if (Protocol(acptr
) < 10)
752 SetFlag(acptr
, FLAG_TS8
);
753 add_client_to_list(acptr
);
759 for (bcptr
= cli_serv(acptr
)->up
; !IsMe(bcptr
); bcptr
= cli_serv(bcptr
)->up
)
760 if (IsBurstOrBurstAck(bcptr
))
763 sendto_opmask_butone(0, SNO_NETWORK
, "Net junction: %s %s",
764 cli_name(sptr
), cli_name(acptr
));
767 * Old sendto_serv_but_one() call removed because we now need to send
768 * different names to different servers (domain name matching).
770 for (i
= 0; i
<= HighestFd
; i
++)
772 if (!(bcptr
= LocalClientArray
[i
]) || !IsServer(bcptr
) ||
773 bcptr
== cptr
|| IsMe(bcptr
))
775 if (0 == match(cli_name(&me
), cli_name(acptr
)))
777 sendcmdto_one(sptr
, CMD_SERVER
, bcptr
, "%s %d 0 %s %s %s%s +%s%s%s :%s",
778 cli_name(acptr
), hop
+ 1, parv
[4], parv
[5],
779 NumServCap(acptr
), IsHub(acptr
) ? "h" : "",
780 IsService(acptr
) ? "s" : "", IsIPv6(acptr
) ? "6" : "",