void checkServer(struct Client *sptr, struct Client *acptr) { char outbuf[BUFSIZE]; /* Header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected at:: %s (%Tu)", myctime(acptr->cli_serv->timestamp), acptr->cli_serv->timestamp); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Server name:: %s", acptr->cli_name); send_reply(sptr, RPL_DATASTR, outbuf); if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) { ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Numeric:: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Users:: %d / %d", (acptr == &me) ? UserStats.local_clients : cli_serv(acptr)->clients, base64toint(cli_serv(acptr)->nn_capacity)); send_reply(sptr, RPL_DATASTR, outbuf); if (IsBurst(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Bursting"); else if (IsBurstAck(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Awaiting EOB Ack"); else if (IsService(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Network Service"); else if (IsHub(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Network Hub"); ircd_snprintf(0, outbuf, sizeof(outbuf), " Class:: %s", get_client_class(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (feature_bool(FEAT_CHECK_EXTENDED)) { int dlinkc = 0; struct DLink* slink = NULL; send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_DATASTR, "Downlinks::"); for (slink = cli_serv(acptr)->down; slink; slink = slink->next) { ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc, IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" : IsService(slink->value.cptr) ? "=" : IsHub(slink->value.cptr) ? "+" : " ", cli_name(slink->value.cptr)); send_reply(sptr, RPL_DATASTR, outbuf); } if (!dlinkc) send_reply(sptr, RPL_DATASTR, "<none>"); } /* Send 'END OF CHECK' message */ send_reply(sptr, RPL_ENDOFCHECK, " "); }
/** Send a server map to a client. * @param[in] cptr Client to who to send the map. * @param[in] server Top-level server to display. * @param[in] mask Mask to filter which servers are shown. * @param[in] prompt_length Number of characters used in prompt. */ static void dump_map(struct Client *cptr, struct Client *server, char *mask, int prompt_length) { const char *chr; static char prompt[64]; struct DLink *lp; char *p = prompt + prompt_length; int cnt = 0; *p = '\0'; if (prompt_length > 60) send_reply(cptr, RPL_MAPMORE, prompt, cli_name(server)); else { char lag[512]; if (cli_serv(server)->lag>10000) lag[0]=0; else if (cli_serv(server)->lag<0) strcpy(lag,"(0s)"); else sprintf(lag,"(%is)",cli_serv(server)->lag); if (IsBurst(server)) chr = "*"; else if (IsBurstAck(server)) chr = "!"; else chr = ""; send_reply(cptr, RPL_MAP, prompt, chr, cli_name(server), lag, (server == &me) ? UserStats.local_clients : cli_serv(server)->clients); } if (prompt_length > 0) { p[-1] = ' '; if (p[-2] == '`') p[-2] = ' '; } if (prompt_length > 60) return; strcpy(p, "|-"); for (lp = cli_serv(server)->down; lp; lp = lp->next) if (match(mask, cli_name(lp->value.cptr))) ClrFlag(lp->value.cptr, FLAG_MAP); else { SetFlag(lp->value.cptr, FLAG_MAP); cnt++; } for (lp = cli_serv(server)->down; lp; lp = lp->next) { if (!HasFlag(lp->value.cptr, FLAG_MAP)) continue; if (--cnt == 0) *p = '`'; dump_map(cptr, lp->value.cptr, mask, prompt_length + 2); } if (prompt_length > 0) p[-1] = '-'; }
static void stats_servers_verbose(struct Client* sptr, struct StatDesc* sd, int stat, char* param) { struct Client *acptr; /* lowercase 'v' is for human-readable, * uppercase 'V' is for machine-readable */ if (stat == 'v') send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, "%-20s %-20s Flags Hops Numeric Lag RTT Up Down " "Clients/Max Proto %-10s :Info", "Servername", "Uplink", "LinkTS"); for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { if (!IsServer(acptr) && !IsMe(acptr)) continue; if (param && match(param, cli_name(acptr))) /* narrow search */ continue; send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, stat == 'v' ? "%-20s %-20s %c%c%c%c %4i %s %-4i %5i %4i %4i %4i %5i %5i " "P%-2i %Tu :%s" : "%s %s %c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s", cli_name(acptr), cli_name(cli_serv(acptr)->up), IsBurst(acptr) ? 'B' : '-', IsBurstAck(acptr) ? 'A' : '-', IsHub(acptr) ? 'H' : '-', IsService(acptr) ? 'S' : '-', cli_hopcount(acptr), NumServ(acptr), base64toint(cli_yxx(acptr)), cli_serv(acptr)->lag, cli_serv(acptr)->asll_rtt, cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from, cli_serv(acptr)->clients, cli_serv(acptr)->nn_mask, cli_serv(acptr)->prot, cli_serv(acptr)->timestamp, cli_info(acptr)); } }
/** Handle a connection that has sent a valid PASS and SERVER. * @param cptr New peer server. * @param aconf Connect block for \a cptr. * @return Zero. */ int server_estab(struct Client *cptr, struct ConfItem *aconf) { struct Client* acptr = 0; const char* inpath; int i; assert(0 != cptr); assert(0 != cli_local(cptr)); inpath = cli_name(cptr); if (IsUnknown(cptr)) { if (aconf->passwd[0]) sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd); /* * Pass my info to the new server */ sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6 :%s", cli_name(&me), cli_serv(&me)->timestamp, cli_serv(cptr)->timestamp, MAJOR_PROTOCOL, NumServCap(&me), feature_bool(FEAT_HUB) ? "h" : "", *(cli_info(&me)) ? cli_info(&me) : "IRCers United"); } det_confs_butmask(cptr, CONF_SERVER); if (!IsHandshake(cptr)) hAddClient(cptr); SetServer(cptr); cli_handler(cptr) = SERVER_HANDLER; Count_unknownbecomesserver(UserStats); SetBurst(cptr); /* nextping = CurrentTime; */ /* * NOTE: check for acptr->user == cptr->serv->user is necessary to insure * that we got the same one... bleah */ if (cli_serv(cptr)->user && *(cli_serv(cptr))->by && (acptr = findNUser(cli_serv(cptr)->by))) { if (cli_user(acptr) == cli_serv(cptr)->user) { sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :Link with %s established.", acptr, inpath); } else { /* * if not the same client, set by to empty string */ acptr = 0; *(cli_serv(cptr))->by = '\0'; } } sendto_opmask(acptr, SNO_OLDSNO, "Link with %s established.", inpath); cli_serv(cptr)->up = &me; cli_serv(cptr)->updown = add_dlink(&(cli_serv(&me))->down, cptr); sendto_opmask(0, SNO_NETWORK, "Net junction: %s %s", cli_name(&me), cli_name(cptr)); SetJunction(cptr); /* * Old sendto_serv_but_one() call removed because we now * need to send different names to different servers * (domain name matching) Send new server to other servers. */ for (i = 0; i <= HighestFd; i++) { if (!(acptr = LocalClientArray[i]) || !IsServer(acptr) || acptr == cptr || IsMe(acptr)) continue; if (!match(cli_name(&me), cli_name(cptr))) continue; sendcmdto_one(&me, CMD_SERVER, acptr, "%s 2 0 %Tu J%02u %s%s +%s%s%s :%s", cli_name(cptr), cli_serv(cptr)->timestamp, Protocol(cptr), NumServCap(cptr), IsHub(cptr) ? "h" : "", IsService(cptr) ? "s" : "", IsIPv6(cptr) ? "6" : "", cli_info(cptr)); } /* Send these as early as possible so that glined users/juped servers can * be removed from the network while the remote server is still chewing * our burst. */ gline_burst(cptr); jupe_burst(cptr); /* * Pass on my client information to the new server * * First, pass only servers (idea is that if the link gets * canceled because the server was already there, * there are no NICK's to be canceled...). Of course, * if cancellation occurs, all this info is sent anyway, * and I guess the link dies when a read is attempted...? --msa * * Note: Link cancellation to occur at this point means * that at least two servers from my fragment are building * up connection this other fragment at the same time, it's * a race condition, not the normal way of operation... */ for (acptr = &me; acptr; acptr = cli_prev(acptr)) { /* acptr->from == acptr for acptr == cptr */ if (cli_from(acptr) == cptr) continue; if (IsServer(acptr)) { const char* protocol_str; if (Protocol(acptr) > 9) protocol_str = IsBurst(acptr) ? "J" : "P"; else protocol_str = IsBurst(acptr) ? "J0" : "P0"; if (0 == match(cli_name(&me), cli_name(acptr))) continue; sendcmdto_one(cli_serv(acptr)->up, CMD_SERVER, cptr, "%s %d 0 %Tu %s%u %s%s +%s%s%s :%s", cli_name(acptr), cli_hopcount(acptr) + 1, cli_serv(acptr)->timestamp, protocol_str, Protocol(acptr), NumServCap(acptr), IsHub(acptr) ? "h" : "", IsService(acptr) ? "s" : "", IsIPv6(acptr) ? "6" : "", cli_info(acptr)); } } for (acptr = &me; acptr; acptr = cli_prev(acptr)) { /* acptr->from == acptr for acptr == cptr */ if (cli_from(acptr) == cptr) continue; if (IsUser(acptr)) { char xxx_buf[25]; char *s = umode_str(acptr); sendcmdto_one(cli_user(acptr)->server, CMD_NICK, cptr, "%s %d %Tu %s %s %s%s%s%s %s%s :%s", cli_name(acptr), cli_hopcount(acptr) + 1, cli_lastnick(acptr), cli_user(acptr)->username, cli_user(acptr)->realhost, *s ? "+" : "", s, *s ? " " : "", iptobase64(xxx_buf, &cli_ip(acptr), sizeof(xxx_buf), IsIPv6(cptr)), NumNick(acptr), cli_info(acptr)); } } /* * Last, send the BURST. * (Or for 2.9 servers: pass all channels plus statuses) */ { struct Channel *chptr; for (chptr = GlobalChannelList; chptr; chptr = chptr->next) send_channel_modes(cptr, chptr); } sendcmdto_one(&me, CMD_END_OF_BURST, cptr, ""); return 0; }
/* * ms_burst - server message handler * * -- by Run [email protected] december 1995 till march 1997 * * parv[0] = sender prefix * parv[1] = channel name * parv[2] = channel timestamp * The meaning of the following parv[]'s depend on their first character: * If parv[n] starts with a '+': * Net burst, additive modes * parv[n] = <mode> * parv[n+1] = <param> (optional) * parv[n+2] = <param> (optional) * If parv[n] starts with a '%', then n will be parc-1: * parv[n] = %<ban> <ban> <ban> ... * If parv[n] starts with another character: * parv[n] = <nick>[:<mode>],<nick>[:<mode>],... * where <mode> is the channel mode (ov) of nick and all following nicks. * * Example: * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2" * * Anti net.ride code. * * When the channel already exist, and its TS is larger then * the TS in the BURST message, then we cancel all existing modes. * If its is smaller then the received BURST message is ignored. * If it's equal, then the received modes are just added. */ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct ModeBuf modebuf, *mbuf = 0; struct Channel *chptr; time_t timestamp; struct Membership *member, *nmember; struct SLink *lp, **lp_p; unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST); int param, nickpos = 0, banpos = 0; char modestr[BUFSIZE], nickstr[BUFSIZE], banstr[BUFSIZE]; if (parc < 3) return protocol_violation(sptr,"Too few parameters for BURST"); if (!IsBurst(sptr)) /* don't allow BURST outside of burst */ return exit_client_msg(cptr, cptr, &me, "HACK: BURST message outside " "net.burst from %s", cli_name(sptr)); if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE))) return 0; /* can't create the channel? */ timestamp = atoi(parv[2]); if (!chptr->creationtime || chptr->creationtime > timestamp) { /* * Kick local members if channel is +i or +k and our TS was larger * than the burst TS (anti net.ride). The modes hack is here because * we have to do this before mode_parse, as chptr may go away. */ for (param = 3; param < parc; param++) { if (parv[param][0] != '+') continue; if (strchr(parv[param], 'i') || strchr(parv[param], 'k')) { /* Clear any outstanding rogue invites */ mode_invite_clear(chptr); for (member = chptr->members; member; member = nmember) { nmember=member->next_member; if (!MyUser(member->user) || IsZombie(member)) continue; sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user); sendcmdto_channel_butserv_butone(&me, CMD_KICK, chptr, NULL, "%H %C :Net Rider", chptr, member->user); make_zombie(member, member->user, &me, &me, chptr); } } break; } /* If the channel had only locals, it went away by now. */ if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE))) return 0; /* can't create the channel? */ } /* turn off burst joined flag */ for (member = chptr->members; member; member = member->next_member) member->status &= ~CHFL_BURST_JOINED; if (!chptr->creationtime) /* mark channel as created during BURST */ chptr->mode.mode |= MODE_BURSTADDED; /* new channel or an older one */ if (!chptr->creationtime || chptr->creationtime > timestamp) { chptr->creationtime = timestamp; modebuf_init(mbuf = &modebuf, &me, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY); modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */ chptr->mode.mode &= ~(MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED | MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS); parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */ /* mark bans for wipeout */ for (lp = chptr->banlist; lp; lp = lp->next) lp->flags |= CHFL_BURST_BAN_WIPEOUT; /* clear topic set by netrider (if set) */ if (*chptr->topic) { *chptr->topic = '\0'; *chptr->topic_nick = '\0'; chptr->topic_time = 0; sendcmdto_channel_butserv_butone(&me, CMD_TOPIC, chptr, NULL, "%H :%s", chptr, chptr->topic); } } else if (chptr->creationtime == timestamp) { modebuf_init(mbuf = &modebuf, &me, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY); parse_flags |= MODE_PARSE_SET; /* set new modes */ } param = 3; /* parse parameters */ while (param < parc) { switch (*parv[param]) { case '+': /* parameter introduces a mode string */ param += mode_parse(mbuf, cptr, sptr, chptr, parc - param, parv + param, parse_flags); break; case '%': /* parameter contains bans */ if (parse_flags & MODE_PARSE_SET) { char *banlist = parv[param] + 1, *p = 0, *ban, *ptr; struct SLink *newban; for (ban = ircd_strtok(&p, banlist, " "); ban; ban = ircd_strtok(&p, 0, " ")) { ban = collapse(pretty_mask(ban)); /* * Yeah, we should probably do this elsewhere, and make it better * and more general; this will hold until we get there, though. * I dislike the current add_banid API... -Kev * * I wish there were a better algo. for this than the n^2 one * shown below *sigh* */ for (lp = chptr->banlist; lp; lp = lp->next) { if (!ircd_strcmp(lp->value.ban.banstr, ban)) { ban = 0; /* don't add ban */ lp->flags &= ~CHFL_BURST_BAN_WIPEOUT; /* not wiping out */ break; /* new ban already existed; don't even repropagate */ } else if (!(lp->flags & CHFL_BURST_BAN_WIPEOUT) && !mmatch(lp->value.ban.banstr, ban)) { ban = 0; /* don't add ban unless wiping out bans */ break; /* new ban is encompassed by an existing one; drop */ } else if (!mmatch(ban, lp->value.ban.banstr)) lp->flags |= CHFL_BAN_OVERLAPPED; /* remove overlapping ban */ if (!lp->next) break; } if (ban) { /* add the new ban to the end of the list */ /* Build ban buffer */ if (!banpos) { banstr[banpos++] = ' '; banstr[banpos++] = ':'; banstr[banpos++] = '%'; } else banstr[banpos++] = ' '; for (ptr = ban; *ptr; ptr++) /* add ban to buffer */ banstr[banpos++] = *ptr; newban = make_link(); /* create new ban */ DupString(newban->value.ban.banstr, ban); DupString(newban->value.ban.who, cli_name(feature_bool(FEAT_HIS_BANWHO) ? &me : sptr)); newban->value.ban.when = TStime(); newban->flags = CHFL_BAN | CHFL_BURST_BAN; /* set flags */ if ((ptr = strrchr(ban, '@')) && check_if_ipmask(ptr + 1)) newban->flags |= CHFL_BAN_IPMASK; newban->next = 0; if (lp) lp->next = newban; /* link it in */ else chptr->banlist = newban; } } } param++; /* look at next param */ break; default: /* parameter contains clients */ { struct Client *acptr; char *nicklist = parv[param], *p = 0, *nick, *ptr; int default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; int last_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; for (nick = ircd_strtok(&p, nicklist, ","); nick; nick = ircd_strtok(&p, 0, ",")) { if ((ptr = strchr(nick, ':'))) { /* new flags; deal */ *ptr++ = '\0'; if (parse_flags & MODE_PARSE_SET) { for (default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; *ptr; ptr++) { if (*ptr == 'o') /* has oper status */ default_mode = (default_mode & ~CHFL_DEOPPED) | CHFL_CHANOP; else if (*ptr == 'v') /* has voice status */ default_mode |= CHFL_VOICE; else /* I don't recognize that flag */ break; /* so stop processing */ } } } if (!(acptr = findNUser(nick)) || cli_from(acptr) != cptr) continue; /* ignore this client */ /* Build nick buffer */ nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */ nickpos++; for (ptr = nick; *ptr; ptr++) /* store nick */ nickstr[nickpos++] = *ptr; if (default_mode != last_mode) { /* if mode changed... */ last_mode = default_mode; nickstr[nickpos++] = ':'; /* add a specifier */ if (default_mode & CHFL_CHANOP) nickstr[nickpos++] = 'o'; if (default_mode & CHFL_VOICE) nickstr[nickpos++] = 'v'; } add_user_to_channel(chptr, acptr, default_mode); sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, "%H", chptr); } } param++; break; } /* switch (*parv[param]) { */ } /* while (param < parc) { */ nickstr[nickpos] = '\0'; banstr[banpos] = '\0'; if (parse_flags & MODE_PARSE_SET) { modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */ modestr[0] = modestr[1] ? ' ' : '\0'; } else modestr[0] = '\0'; sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr, chptr->creationtime, modestr, nickstr, banstr); if (parse_flags & MODE_PARSE_WIPEOUT || banpos) mode_ban_invalidate(chptr); if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */ /* first deal with channel members */ for (member = chptr->members; member; member = member->next_member) { if (member->status & CHFL_BURST_JOINED) { /* joined during burst */ if (member->status & CHFL_CHANOP) modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user); if (member->status & CHFL_VOICE) modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user); } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */ if (member->status & CHFL_CHANOP) modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user); if (member->status & CHFL_VOICE) modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user); member->status = ((member->status & ~(CHFL_CHANOP | CHFL_VOICE)) | CHFL_DEOPPED); } } /* Now deal with channel bans */ lp_p = &chptr->banlist; while (*lp_p) { lp = *lp_p; /* remove ban from channel */ if (lp->flags & (CHFL_BAN_OVERLAPPED | CHFL_BURST_BAN_WIPEOUT)) { modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN, lp->value.ban.banstr, 1); /* let it free banstr */ *lp_p = lp->next; /* clip out of list */ MyFree(lp->value.ban.who); /* free who */ free_link(lp); /* free ban */ continue; } else if (lp->flags & CHFL_BURST_BAN) /* add ban to channel */ modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN, lp->value.ban.banstr, 0); /* don't free banstr */ lp->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* reset the flag */ lp_p = &(*lp_p)->next; } } return mbuf ? modebuf_flush(mbuf) : 0; }
static int do_server_estab(aClient *cptr) { aClient *acptr; aConnect *aconn; aChannel *chptr; int i; /* "refresh" inpath with host */ char *inpath = get_client_name(cptr, HIDEME); SetServer(cptr); Count.unknown--; Count.server++; Count.myserver++; if(IsZipCapable(cptr) && DoZipThis(cptr)) { sendto_one(cptr, "SVINFO ZIP"); SetZipOut(cptr); cptr->serv->zip_out = zip_create_output_session(); } #ifdef MAXBUFFERS /* let's try to bump up server sock_opts... -Taner */ reset_sock_opts(cptr->fd, 1); #endif /* adds to server list */ add_to_list(&server_list, cptr); set_effective_class(cptr); /* Check one more time for good measure... is it there? */ if ((acptr = find_name(cptr->name, NULL))) { char nbuf[HOSTLEN * 2 + USERLEN + 5]; aClient *bcptr; /* * While negotiating stuff, another copy of this server appeared. * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon */ bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr : acptr->from; sendto_one(bcptr, "ERROR :Server %s already exists", cptr->name); if (bcptr == cptr) { sendto_gnotice("from %s: Link %s cancelled, server %s already " "exists (final phase)", me.name, get_client_name(bcptr, HIDEME), cptr->name); sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, " "server %s already exists (final phase)", me.name, get_client_name(bcptr, HIDEME), cptr->name); return exit_client(bcptr, bcptr, &me, "Server Exists (final phase)"); } /* inform all those who care (set +n) -epi */ strcpy(nbuf, get_client_name(bcptr, HIDEME)); sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced " "by %s (final phase)", me.name, nbuf, cptr->name, get_client_name(cptr, HIDEME)); sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s " "reintroduced by %s (final phase)", me.name, nbuf, cptr->name, get_client_name(cptr, HIDEME)); exit_client(bcptr, bcptr, &me, "Server Exists (final phase)"); } /* error, error, error! if a server is U:'d, and it connects to us, * we need to figure that out! So, do it here. - lucas */ if (find_aUserver(cptr->name)) { Count.myulined++; cptr->flags |= FLAGS_ULINE; /* If the server has special u:line flags, let's set them.. */ cptr->serv->uflags = cptr->serv->aconn->uflags; } fakelinkserver_update(cptr->name, cptr->info); sendto_gnotice("from %s: Link with %s established, states:%s%s%s%s", me.name, inpath, ZipOut(cptr) ? " Output-compressed" : "", RC4EncLink(cptr) ? " encrypted" : "", IsULine(cptr) ? " ULined" : "", DoesTS(cptr) ? " TS" : " Non-TS"); /* * Notify everyone of the fact that this has just linked: the entire * network should get two of these, one explaining the link between * me->serv and the other between serv->me */ sendto_serv_butone(NULL, ":%s GNOTICE :Link with %s established: %s", me.name, inpath, DoesTS(cptr) ? "TS link" : "Non-TS link!"); add_to_client_hash_table(cptr->name, cptr); /* add it to scache */ find_or_add(cptr->name); /* * Old sendto_serv_but_one() call removed because we now need to * send different names to different servers (domain name * matching) Send new server to other servers. */ for (i = 0; i <= highest_fd; i++) { if (!(acptr = local[i]) || !IsServer(acptr) || acptr == cptr || IsMe(acptr)) continue; if ((aconn = acptr->serv->aconn) && !match(my_name_for_link(me.name, aconn), cptr->name)) continue; sendto_one(acptr, ":%s SERVER %s 2 :%s", me.name, cptr->name, cptr->info); } /* * Pass on my client information to the new server * * First, pass only servers (idea is that if the link gets * cancelled beacause the server was already there, there are no * NICK's to be cancelled...). Of course, if cancellation occurs, * all this info is sent anyway, and I guess the link dies when a * read is attempted...? --msa * * Note: Link cancellation to occur at this point means that at * least two servers from my fragment are building up connection * this other fragment at the same time, it's a race condition, * not the normal way of operation... * * ALSO NOTE: using the get_client_name for server names-- see * previous *WARNING*!!! (Also, original inpath is * destroyed...) */ aconn = cptr->serv->aconn; for (acptr = &me; acptr; acptr = acptr->prev) { if (acptr->from == cptr) continue; if (IsServer(acptr)) { if (match(my_name_for_link(me.name, aconn), acptr->name) == 0) continue; sendto_one(cptr, ":%s SERVER %s %d :%s", acptr->serv->up, acptr->name, acptr->hopcount + 1, acptr->info); } } /* send out our SQLINES and SGLINES too */ send_simbans(cptr, SBAN_CHAN|SBAN_NETWORK); send_simbans(cptr, SBAN_NICK|SBAN_NETWORK); send_simbans(cptr, SBAN_GCOS|SBAN_NETWORK); /* Send out fake server list and other 'fake' stuff */ fakeserver_sendserver(cptr); /* Send UHM (user host-masking) type */ if(confopts & FLAGS_HUB) sendto_one(cptr, "SVSUHM %d", uhm_type); /* send clone list */ clones_send(cptr); /* Bursts are about to start.. send a BURST */ if (IsBurst(cptr)) sendto_one(cptr, "BURST"); /* * * Send it in the shortened format with the TS, if it's a TS * server; walk the list of channels, sending all the nicks that * haven't been sent yet for each channel, then send the channel * itself -- it's less obvious than sending all nicks first, but * on the receiving side memory will be allocated more nicely * saving a few seconds in the handling of a split -orabidoo */ { chanMember *cm; static char nickissent = 1; nickissent = 3 - nickissent; /* * flag used for each nick to check if we've sent it yet - must * be different each time and !=0, so we alternate between 1 and * 2 -orabidoo */ for (chptr = channel; chptr; chptr = chptr->nextch) { for (cm = chptr->members; cm; cm = cm->next) { acptr = cm->cptr; if (acptr->nicksent != nickissent) { acptr->nicksent = nickissent; if (acptr->from != cptr) sendnick_TS(cptr, acptr); } } send_channel_modes(cptr, chptr); } /* also send out those that are not on any channel */ for (acptr = &me; acptr; acptr = acptr->prev) if (acptr->nicksent != nickissent) { acptr->nicksent = nickissent; if (acptr->from != cptr) sendnick_TS(cptr, acptr); } } if(confopts & FLAGS_HUB) fakelusers_sendlock(cptr); if(ZipOut(cptr)) { unsigned long inb, outb; double rat; zip_out_get_stats(cptr->serv->zip_out, &inb, &outb, &rat); if(inb) { sendto_gnotice("from %s: Connect burst to %s: %lu bytes normal, " "%lu compressed (%3.2f%%)", me.name, get_client_name(cptr, HIDEME), inb, outb, rat); sendto_serv_butone(cptr, ":%s GNOTICE :Connect burst to %s: %lu " "bytes normal, %lu compressed (%3.2f%%)", me.name, get_client_name(cptr, HIDEME), inb, outb, rat); } } /* stuff a PING at the end of this burst so we can figure out when the other side has finished processing it. */ cptr->flags |= FLAGS_BURST|FLAGS_PINGSENT; if (IsBurst(cptr)) cptr->flags |= FLAGS_SOBSENT; sendto_one(cptr, "PING :%s", me.name); return 0; }
static void dump_map(struct Client *cptr, struct Client *server, char *mask, int prompt_length) { static char prompt[64]; struct DLink *lp; char *p = &prompt[prompt_length]; int cnt = 0; *p = '\0'; if (prompt_length > 60) send_reply(cptr, RPL_MAPMORE, prompt, cli_name(server)); else { char lag[512]; int showserv = 1; unsigned int totalusers = UserStats.clients; unsigned int percentage; unsigned int serv_clients; if (totalusers == 0) totalusers = 1; /* ¿? NO deberia ocurrir nunca... */ percentage = (10000 * (IsMe(server) ? UserStats.local_clients : cli_serv(server)->clients)) / totalusers; if (IsMe(server)) strcpy(lag,"(0s)"); else if (cli_serv(server)->lag>10000) lag[0]=0; else if (cli_serv(server)->lag<0) strcpy(lag,"(0s)"); else sprintf(lag,"(%is)",cli_serv(server)->lag); if (IsHiddenserv(server) && !feature_bool(FEAT_SHOWSERVON_MAP)) if (!IsAnOper(cptr) && !es_representante(cptr)) showserv = 0; serv_clients = (server == &me) ? UserStats.local_clients : cli_serv(server)->clients; send_reply(cptr, RPL_MAP, prompt, ( (IsBurst(server)) ? "*" : (IsBurstAck(server) ? "!" : "")), showserv ? cli_name(server) : feature_str(FEAT_HIS_SERVERNAME), lag, NumServ(server), base64toint(NumServ(server)), serv_clients, (serv_clients == 1) ? "" : "s", (percentage / 100), (percentage % 100)); } if (prompt_length > 0) { p[-1] = ' '; if (p[-2] == '`') p[-2] = ' '; } if (prompt_length > 60) return; strcpy(p, "|-"); for (lp = cli_serv(server)->down; lp; lp = lp->next) if (match(mask, cli_name(lp->value.cptr))) cli_flags(lp->value.cptr) &= ~FLAGS_MAP; else { cli_flags(lp->value.cptr) |= FLAGS_MAP; cnt++; } for (lp = cli_serv(server)->down; lp; lp = lp->next) { if ((cli_flags(lp->value.cptr) & FLAGS_MAP) == 0) continue; if (--cnt == 0) *p = '`'; dump_map(cptr, lp->value.cptr, mask, prompt_length + 2); } if (prompt_length > 0) p[-1] = '-'; }