示例#1
0
文件: s_serv.c 项目: jast/ircu-now
/** 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;
}
示例#2
0
void checkClient(struct Client *sptr, struct Client *acptr)
{
   struct Channel *chptr;
   struct Membership *lp;
   char outbuf[BUFSIZE];
   char *privs;
   time_t nowr;

   /* Header */
   send_reply(sptr, RPL_DATASTR, " ");
   send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name);
   send_reply(sptr, RPL_DATASTR, " ");

   ircd_snprintf(0, outbuf, sizeof(outbuf), "           Nick:: %s (%s%s)", acptr->cli_name, NumNick(acptr));
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (MyUser(acptr))
   {  
      ircd_snprintf(0, outbuf, sizeof(outbuf),  "      Signed on:: %s", myctime(acptr->cli_firsttime));
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   ircd_snprintf(0, outbuf, sizeof(outbuf), "      Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick);
   send_reply(sptr, RPL_DATASTR, outbuf);

   ircd_snprintf(0, outbuf, sizeof(outbuf), "  User/Hostmask:: %s@%s (%s)", acptr->cli_user->username, acptr->cli_user->host,
   ircd_ntoa((const char*) &(cli_ip(acptr))));
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (((feature_int(FEAT_HOST_HIDING_STYLE) == 1) ? HasHiddenHost(acptr) : IsHiddenHost(acptr)) || IsSetHost(acptr))
   {
      ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", acptr->cli_user->realusername, acptr->cli_user->realhost);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   ircd_snprintf(0, outbuf, sizeof(outbuf), "      Real Name:: %s%c", cli_info(acptr), COLOR_OFF);
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (IsService(cli_user(acptr)->server)) {
     if (acptr)
       send_reply(sptr, RPL_DATASTR, "         Status:: Network Service");
     else if (IsAdmin(acptr))
       send_reply(sptr, RPL_DATASTR, "         Status:: IRC Administrator (service)");
     else if (IsAnOper(acptr))
       send_reply(sptr, RPL_DATASTR, "         Status:: IRC Operator (service)");
     else 
       send_reply(sptr, RPL_DATASTR, "         Status:: Client (service)");
   } else if (IsAdmin(acptr)) {
     send_reply(sptr, RPL_DATASTR, "         Status:: IRC Administrator");
   } else if (IsAnOper(acptr)) {
     send_reply(sptr, RPL_DATASTR, "         Status:: IRC Operator");
   } else {
     send_reply(sptr, RPL_DATASTR, "         Status:: Client");
   }

   if (MyUser(acptr)) {
     ircd_snprintf(0, outbuf, sizeof(outbuf), "          Class:: %s", get_client_class(acptr));
     send_reply(sptr, RPL_DATASTR, outbuf);
   }

   privs = client_print_privs(acptr);
   if (strlen(privs) > 1)
     client_check_privs(acptr, sptr);

   ircd_snprintf(0, outbuf, sizeof(outbuf), "   Connected to:: %s", cli_name(acptr->cli_user->server));
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (cli_version(acptr)) {
     if (strlen(cli_version(acptr)) > 0) {
       ircd_snprintf(0, outbuf, sizeof(outbuf), "   CTCP Version:: %s", cli_version(acptr));
       send_reply(sptr, RPL_DATASTR, outbuf);
     }
   }

   if (cli_user(acptr) && !EmptyString(cli_user(acptr)->swhois)) {
     ircd_snprintf(0, outbuf, sizeof(outbuf), "         SWHOIS:: %s", cli_user(acptr)->swhois);
     send_reply(sptr, RPL_DATASTR, outbuf);
   }

   if (cli_webirc(acptr)) {
     if (strlen(cli_webirc(acptr)) > 0) {
       ircd_snprintf(0, outbuf, sizeof(outbuf), "         WebIRC:: %s", cli_webirc(acptr));
       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);
   }

   if (MyUser(acptr))
     get_eflags(sptr, acptr);

   /* +s (SERV_NOTICE) is not relayed to us from remote servers,
    * so we cannot tell if a remote client has that mode set.
    * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG
    * (and breaks if the user is +r) so we won't do that either.
    */

   if (strlen(umode_str(acptr)) < 1)
      strcpy(outbuf, "       Umode(s):: <none>");
   else
      ircd_snprintf(0, outbuf, sizeof(outbuf), "       Umode(s):: +%s", umode_str(acptr));

   send_reply(sptr, RPL_DATASTR, outbuf);

   if (acptr->cli_user->joined == 0)
      send_reply(sptr, RPL_DATASTR, "     Channel(s):: <none>");
   else if (acptr->cli_user->joined > 50) 
   {

      /* NB. As a sanity check, we DO NOT show the individual channels the
       *     client is on if it is on > 50 channels.  This is to prevent the ircd
       *     barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine
       *     an Oper would want to see every single channel 'x' client is on anyway if
       *     they are on *that* many).
       */

      ircd_snprintf(0, outbuf, sizeof(outbuf), "     Channel(s):: - (total: %u)", acptr->cli_user->joined);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }
   else
   {
      char chntext[BUFSIZE];
      int len = strlen("     Channel(s):: ");
      int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
      *chntext = '\0';

      strcpy(chntext, "     Channel(s):: ");
      for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
         chptr = lp->channel;
         if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
            send_reply(sptr, RPL_DATASTR, chntext);
            *chntext = '\0';
            strcpy(chntext, "     Channel(s):: ");
            len = strlen(chntext);
         }
         if (IsDeaf(acptr))
            *(chntext + len++) = '-';
         if (is_chan_op(acptr, chptr))
            *(chntext + len++) = '@';
         if (is_half_op(acptr, chptr))
            *(chntext + len++) = '%';
         if (IsOper(sptr) && !ShowChannel(sptr,chptr))
            *(chntext + len++) = '*';
         if (IsZombie(lp))
            *(chntext + len++) = '!';
         if (len)
            *(chntext + len) = '\0';

         strcpy(chntext + len, chptr->chname);
         len += strlen(chptr->chname);
         strcat(chntext + len, " ");
         len++;
      }

      if (chntext[0] != '\0')
        send_reply(sptr, RPL_DATASTR, chntext);
   }

   /* If client processing command ISN'T target (or a registered
    * Network Service), show idle time since the last time we
    * parsed something.
    */
   if (MyUser(acptr) && !(IsService(acptr) == -1) && !(strCasediff(acptr->cli_name, sptr->cli_name) == 0)) {
      nowr = CurrentTime - acptr->cli_user->last;
      ircd_snprintf(0, outbuf, sizeof(outbuf), "       Idle for:: %d days, %02ld:%02ld:%02ld",
         nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   /* Away message (if applicable) */
   if (acptr->cli_user->away) {
      ircd_snprintf(0, outbuf, sizeof(outbuf), "   Away message:: %s", acptr->cli_user->away);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   /* If local user.. */

   if (MyUser(acptr)) {
      send_reply(sptr, RPL_DATASTR, " ");
      ircd_snprintf(0, outbuf, sizeof(outbuf), "          Ports:: %d -> %d (client -> server)",
         cli_port(acptr), cli_listener(acptr)->port);
      send_reply(sptr, RPL_DATASTR, outbuf);
      if (feature_bool(FEAT_CHECK_EXTENDED)) {
        /* Note: sendq = receiveq for a client (it makes sense really) */
        ircd_snprintf(0, outbuf, sizeof(outbuf), "      Data sent:: %u.%0.3u Kb (%u protocol messages)",
           cli_receiveK(acptr), cli_receiveB(acptr), cli_receiveM(acptr));
        send_reply(sptr, RPL_DATASTR, outbuf);                          
        ircd_snprintf(0, outbuf, sizeof(outbuf), "  Data received:: %u.%0.3u Kb (%u protocol messages)",
           cli_sendK(acptr), cli_sendB(acptr), cli_sendM(acptr));                                       
        send_reply(sptr, RPL_DATASTR, outbuf);
        ircd_snprintf(0, outbuf, sizeof(outbuf), "  receiveQ size:: %d bytes (max. %d bytes)",
           DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD));
        send_reply(sptr, RPL_DATASTR, outbuf);
        ircd_snprintf(0, outbuf, sizeof(outbuf), "     sendQ size:: %d bytes (max. %d bytes)",
           DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr));                                
        send_reply(sptr, RPL_DATASTR, outbuf);                
      }
   }
   
   /* Send 'END OF CHECK' message */
   send_reply(sptr, RPL_ENDOFCHECK, " ");
}