static void serv_info(aClient *cptr, char *name) { static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :%u %u %s"; long sendK, receiveK, uptime; aClient *acptr; DLink *lp; int i = 0; sendK = receiveK = 0; for (lp = server_list; lp; lp = lp->next) { acptr = lp->value.cptr; #ifdef HIDEULINEDSERVS if (IsULine(acptr) && !IsAnOper(cptr)) continue; #endif sendK += acptr->sendK; receiveK += acptr->receiveK; sendto_one(cptr, Lformat, me.name, RPL_STATSLINKINFO, name, ( (MyClient(cptr) && IsAdmin(cptr)) ? get_client_name(acptr, FALSE) : get_client_name(acptr, HIDEME) ), (int) SBufLength(&acptr->sendQ), (int) acptr->sendM, (int) acptr->sendK, (int) acptr->receiveM, (int) acptr->receiveK, timeofday - acptr->firsttime, timeofday - acptr->since, IsServer(acptr) ? (DoesTS(acptr) ? "TS" : "NoTS") : "-"); if(RC4EncLink(acptr)) sendto_one(cptr, ":%s %d %s : - RC4 encrypted", me.name, RPL_STATSDEBUG, name); if(ZipOut(acptr)) { unsigned long ib, ob; double rat; zip_out_get_stats(acptr->serv->zip_out, &ib, &ob, &rat); if(ib) { sendto_one(cptr, ":%s %d %s : - [O] Zip inbytes %lu, " "outbytes %lu (%3.2f%%)", me.name, RPL_STATSDEBUG, name, ib, ob, rat); } } if(ZipIn(acptr)) { unsigned long ib, ob; double rat; zip_in_get_stats(acptr->serv->zip_in, &ib, &ob, &rat); if(ob) { sendto_one(cptr, ":%s %d %s : - [I] Zip inbytes %lu, " "outbytes %lu (%3.2f%%)", me.name, RPL_STATSDEBUG, name, ib, ob, rat); } } i++; } sendto_one(cptr, ":%s %d %s :%u total server%s", me.name, RPL_STATSDEBUG, name, i, (i == 1) ? "" : "s"); sendto_one(cptr, ":%s %d %s :Sent total : %7.2f %s", me.name, RPL_STATSDEBUG, name, _GMKv(sendK), _GMKs(sendK)); sendto_one(cptr, ":%s %d %s :Recv total : %7.2f %s", me.name, RPL_STATSDEBUG, name, _GMKv(receiveK), _GMKs(receiveK)); uptime = (timeofday - me.since); sendto_one(cptr, ":%s %d %s :Server send: %7.2f %s (%4.1f K/s total," " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name, _GMKv(me.sendK), _GMKs(me.sendK), (float) ((float) me.sendK / (float) uptime), curSendK); sendto_one(cptr, ":%s %d %s :Server recv: %7.2f %s (%4.1f K/s total," " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name, _GMKv(me.receiveK), _GMKs(me.receiveK), (float) ((float) me.receiveK / (float) uptime), curRecvK); }
static int m_server_estab(aClient *cptr) { aConnect *aconn; aClient *acptr; char *inpath, *host, *s, *encr; inpath = get_client_name(cptr, HIDEME); /* "refresh" inpath with host */ host = cptr->name; if (!(aconn = cptr->serv->aconn)) { ircstp->is_ref++; sendto_one(cptr, "ERROR :Lost Connect block"); sendto_ops_lev(ADMIN_LEV, "Lost Connect block for server %s", get_client_name(cptr, TRUE)); return exit_client(cptr, cptr, cptr, "Lost Connect block"); } encr = cptr->passwd; if (*aconn->apasswd && !StrEq(aconn->apasswd, encr)) { ircstp->is_ref++; sendto_one(cptr, "ERROR :Wrong link password"); sendto_ops("Link %s dropped, wrong password", inpath); return exit_client(cptr, cptr, cptr, "Bad Password"); } memset(cptr->passwd, '\0', sizeof(cptr->passwd)); if ((acptr = find_client(host, NULL))) { /* Don't complain about juped servers */ if(!IsULine(acptr) || find_aUserver(acptr->name)) { sendto_gnotice("from %s: Link %s dropped, server already exists", me.name, inpath); sendto_serv_butone(cptr, ":%s GNOTICE :Link %s dropped, server already" " exists", me.name, inpath); } return exit_client(cptr, cptr, cptr, "Server Exists"); } if(!(confopts & FLAGS_HUB)) { int i; for (i = 0; i <= highest_fd; i++) if (local[i] && IsServer(local[i])) { ircstp->is_ref++; sendto_one(cptr, "ERROR :I'm a leaf not a hub"); return exit_client(cptr, cptr, cptr, "I'm a leaf"); } } /* aconf->port is a CAPAB field, kind-of. kludge. mm, mm. */ /* no longer! this should still get better though */ if((aconn->flags & CONN_ZIP)) SetZipCapable(cptr); if((aconn->flags & CONN_DKEY)) SetWantDKEY(cptr); if (IsUnknown(cptr)) { if (aconn->cpasswd[0]) sendto_one(cptr, "PASS %s :TS", aconn->cpasswd); /* Pass my info to the new server */ #ifdef HAVE_ENCRYPTION_ON if(!WantDKEY(cptr)) sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP " "NICKIP NICKIPSTR TSMODE"); else sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT DKEY " "ZIP NICKIP NICKIPSTR TSMODE"); #else sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP NICKIP NICKIPSTR TSMODE"); #endif sendto_one(cptr, "SERVER %s 1 :%s", my_name_for_link(me.name, aconn), (me.info[0]) ? (me.info) : "IRCers United"); } else { s = (char *) strchr(aconn->host, '@'); *s = '\0'; /* should never be NULL -- wanna bet? -Dianora */ Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]", aconn->host, cptr->username)); if (match(aconn->host, cptr->username)) { *s = '@'; ircstp->is_ref++; sendto_ops("Username mismatch [%s]v[%s] : %s", aconn->host, cptr->username, get_client_name(cptr, HIDEME)); sendto_one(cptr, "ERROR :No Username Match"); return exit_client(cptr, cptr, cptr, "Bad User"); } *s = '@'; } /* send routing notice, this should never happen anymore */ if (!DoesTS(cptr)) { sendto_gnotice("from %s: Warning: %s linked, non-TS server", me.name, get_client_name(cptr, HIDEME)); sendto_serv_butone(cptr, ":%s GNOTICE :Warning: %s linked, non-TS server", me.name, get_client_name(cptr, HIDEME)); } sendto_one(cptr, "SVINFO %d %d 0 :%ld", TS_CURRENT, TS_MIN, (ts_val) timeofday); /* sendto one(cptr, "CAPAB ...."); moved to after PASS but before SERVER * now in two places.. up above and in s_bsd.c. - lucas * This is to make sure we pass on our capabilities before we establish * a server connection */ /* * *WARNING* * In the following code in place of plain * server's name we send what is returned by * get_client_name which may add the "sockhost" after the name. * It's *very* *important* that there is a SPACE between * the name and sockhost (if present). The receiving server * will start the information field from this first blank and * thus puts the sockhost into info. ...a bit tricky, but * you have been warned, besides code is more neat this way... * --msa */ cptr->serv->up = me.name; cptr->serv->aconn = aconn; throttle_remove(cipntoa(cptr)); #ifdef HAVE_ENCRYPTION_ON if(!CanDoDKEY(cptr) || !WantDKEY(cptr)) return do_server_estab(cptr); else { SetNegoServer(cptr); /* VERY IMPORTANT THAT THIS IS HERE */ sendto_one(cptr, "DKEY START"); } #else return do_server_estab(cptr); #endif return 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; }
/* * mr_server - SERVER message handler * parv[0] = sender prefix * parv[1] = servername * parv[2] = serverinfo/hopcount * parv[3] = serverinfo */ static void mr_server(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char info[REALLEN + 1]; char *name; struct Client *target_p; int hop; if (parc < 4) { sendto_one(client_p,"ERROR :No servername"); exit_client(client_p, client_p, client_p, "Wrong number of args"); return; } name = parv[1]; hop = atoi(parv[2]); strlcpy(info, parv[3], REALLEN); /* * Reject a direct nonTS server connection if we're TS_ONLY -orabidoo */ if (!DoesTS(client_p)) { sendto_realops_flags(FLAGS_ALL, L_ADMIN,"Link %s dropped, non-TS server", get_client_name(client_p, HIDE_IP)); sendto_realops_flags(FLAGS_ALL, L_OPER,"Link %s dropped, non-TS server", get_client_name(client_p, MASK_IP)); exit_client(client_p, client_p, client_p, "Non-TS server"); return; } if (bogus_host(name)) { exit_client(client_p, client_p, client_p, "Bogus server name"); return; } /* Now we just have to call check_server and everything should be * check for us... -A1kmm. */ switch (check_server(name, client_p, CHECK_SERVER_NOCRYPTLINK)) { case -1: if (ConfigFileEntry.warn_no_nline) { sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Unauthorized server connection attempt from %s: No entry for " "servername %s", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Unauthorized server connection attempt from %s: No entry for " "servername %s", get_client_name(client_p, MASK_IP), name); } exit_client(client_p, client_p, client_p, "Invalid servername."); return; /* NOT REACHED */ break; case -2: sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Unauthorized server connection attempt from %s: Bad password " "for server %s", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Unauthorized server connection attempt from %s: Bad password " "for server %s", get_client_name(client_p, MASK_IP), name); exit_client(client_p, client_p, client_p, "Invalid password."); return; /* NOT REACHED */ break; case -3: sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Unauthorized server connection attempt from %s: Invalid host " "for server %s", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Unauthorized server connection attempt from %s: Invalid host " "for server %s", get_client_name(client_p, MASK_IP), name); exit_client(client_p, client_p, client_p, "Invalid host."); return; /* NOT REACHED */ break; /* servername is > HOSTLEN */ case -4: sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Invalid servername %s from %s", name, get_client_name(client_p, HIDE_IP)); sendto_realops_flags(FLAGS_ALL, L_OPER, "Invalid servername %s from %s", name, get_client_name(client_p, MASK_IP)); exit_client(client_p, client_p, client_p, "Invalid servername."); return; /* NOT REACHED */ break; } if ((target_p = server_exists(name))) { /* * This link is trying feed me a server that I already have * access through another path -- multiple paths not accepted * currently, kill this link immediately!! * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon * * Definitely don't do that here. This is from an unregistered * connect - A1kmm. */ sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Attempt to re-introduce server %s from %s", name, get_client_name(client_p, HIDE_IP)); sendto_realops_flags(FLAGS_ALL, L_OPER, "Attempt to re-introduce server %s from %s", name, get_client_name(client_p, MASK_IP)); sendto_one(client_p, "ERROR :Server already exists."); exit_client(client_p, client_p, client_p, "Server Exists"); return; } if(ServerInfo.hub && IsCapable(client_p, CAP_LL)) { if(IsCapable(client_p, CAP_HUB)) { ClearCap(client_p,CAP_LL); sendto_realops_flags(FLAGS_ALL, L_ALL, "*** LazyLinks to a hub from a hub, thats a no-no."); } else { client_p->localClient->serverMask = nextFreeMask(); if(!client_p->localClient->serverMask) { sendto_realops_flags(FLAGS_ALL, L_ALL, "serverMask is full!"); /* try and negotiate a non LL connect */ ClearCap(client_p,CAP_LL); } } } else if (IsCapable(client_p, CAP_LL)) { if(!IsCapable(client_p, CAP_HUB)) { ClearCap(client_p,CAP_LL); sendto_realops_flags(FLAGS_ALL, L_ALL, "*** LazyLinks to a leaf from a leaf, thats a no-no."); } } /* * if we are connecting (Handshake), we already have the name from the * C:line in client_p->name */ strlcpy(client_p->name, name, HOSTLEN+1); set_server_gecos(client_p, info); client_p->hopcount = hop; server_estab(client_p); }