Пример #1
0
/*
 * ms_links - server message handler
 *
 * parv[0] = sender prefix
 * parv[1] = servername mask
 *
 * or
 *
 * parv[0] = sender prefix
 * parv[1] = server to query
 * parv[2] = servername mask
 */
int
ms_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
   char *mask;
   struct Client *acptr;

   if (parc > 2)
   {
     if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) !=
         HUNTED_ISME)
       return 0;
     mask = parv[2];
   }
   else
     mask = parc < 2 ? 0 : parv[1];
 
   for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr))
   {
     if (!IsServer(acptr) && !IsMe(acptr))
       continue;
     if (!BadPtr(mask) && match(mask, cli_name(acptr)))
       continue;
     send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up),
                cli_hopcount(acptr), cli_serv(acptr)->prot,
                ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)"));
   }
 
   send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask);
   return 0;
 }
Пример #2
0
/** Register numeric of new (remote) client.
 * See @ref numnicks for more details.
 * Add it to the appropriate client_list.
 * @param[in] acptr %User being registered.
 * @param[in] yxx User's numnick.
 */
void SetRemoteNumNick(struct Client* acptr, const char *yxx)
{
    struct Client** acptrp;
    struct Client*  server = cli_user(acptr)->server;

    if (5 == strlen(yxx)) {
        strcpy(cli_yxx(acptr), yxx + 2);
    }
    else {
        (cli_yxx(acptr))[0] = *++yxx;
        (cli_yxx(acptr))[1] = *++yxx;
        (cli_yxx(acptr))[2] = 0;
    }
    Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr),
           base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask));

    acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask];
    if (*acptrp) {
        /*
         * this exits the old client in the array, not the client
         * that is being set
         */
        exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)");
    }
    *acptrp = acptr;
}
Пример #3
0
/*
 * mo_asll - oper message handler
 */
int mo_asll(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char *mask;
  struct Client *acptr;
  int hits;
  int i;

  if (parc < 2)
    return need_more_params(sptr, "ASLL");

  if (parc == 2 && MyUser(sptr))
    parv[parc++] = cli_name(&me);

  if (hunt_server_prio_cmd(sptr, CMD_ASLL, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME)
    return 0;
  mask = parv[1];

  for (i = hits = 0; i <= HighestFd; i++) {
    acptr = LocalClientArray[i];
    if (!acptr || !IsServer(acptr) || !MyConnect(acptr) || match(mask, cli_name(acptr)))
      continue;
    send_asll_reply(&me, sptr, cli_name(acptr), cli_serv(acptr)->asll_rtt,
      cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from);
    hits++;
  }
  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :AsLL for %s: %d local servers matched", sptr, mask, hits);
  return 0;
}
Пример #4
0
/**
 * Removes all clients and downlinks (+clients) of any server
 * QUITs are generated and sent to local users.
 * @param cptr server that must have all dependents removed
 * @param sptr source who thought that this was a good idea
 * @param comment comment sent as sign off message to local clients
 */
static void exit_downlinks(struct Client *cptr, struct Client *sptr, char *comment)
{
  struct Client *acptr;
  struct DLink *next;
  struct DLink *lp;
  struct Client **acptrp;
  int i;

  /* Run over all its downlinks */
  for (lp = cli_serv(cptr)->down; lp; lp = next)
  {
    next = lp->next;
    acptr = lp->value.cptr;
    /* Remove the downlinks and client of the downlink */
    exit_downlinks(acptr, sptr, comment);
    /* Remove the downlink itself */
    exit_one_client(acptr, cli_name(&me));
  }
  /* Remove all clients of this server */
  acptrp = cli_serv(cptr)->client_list;
  for (i = 0; i <= cli_serv(cptr)->nn_mask; ++acptrp, ++i) {
    if (*acptrp)
      exit_one_client(*acptrp, comment);
  }
}
Пример #5
0
/*
 * mr_error - unregistered client message handler
 *
 * parv[0] = sender prefix
 * parv[parc-1] = text
 */
int mr_error(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  const char *para;

  if (!IsHandshake(cptr) && !IsConnecting(cptr))
    return 0; /* ignore ERROR from regular clients */

  para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";

  Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", cli_name(sptr), para));

  if (cptr == sptr)
    sendto_opmask_butone(0, SNO_OLDSNO, "ERROR :from %C -- %s", cptr, para);
  else
    sendto_opmask_butone(0, SNO_OLDSNO, "ERROR :from %C via %C -- %s", sptr,
			 cptr, para);

  if (cli_serv(sptr))
  {
    MyFree(cli_serv(sptr)->last_error_msg);
    DupString(cli_serv(sptr)->last_error_msg, para);
  }

  return 0;
}
Пример #6
0
/** Send a server notice out across the network before sending to all
 * users subscribing to the indicated \a mask except for \a one.
 * @param[in] from Client TOK_SNO is sent from.
 * @param[in] mask One of the SNO_* constants.
 * @param[in] pattern Format string for server notice.
 */
void sendto_opmask_butone_global(struct Client *one, unsigned int mask,
				 const char *pattern, ...)
{
  va_list vl;
  struct VarData vd;
  struct MsgBuf *mb;
  struct DLink *lp;

  va_start(vl, pattern);

  if (cli_serv(&me) && (lp = cli_serv(&me)->down)) {
    vd.vd_format = pattern;
    va_copy(vd.vd_args, vl);
    mb = msgq_make(&me, "%C " TOK_SNO " %d :%v", &me, mask, &vd);

    for (lp = cli_serv(&me)->down; lp; lp = lp->next) {
      if (one && lp->value.cptr == cli_from(one))
        continue;
      send_buffer(lp->value.cptr, mb, 0);
    }

    msgq_clean(mb);
  }

  vsendto_opmask_butone(&me, one, mask, pattern, vl);
  va_end(vl);
}
Пример #7
0
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, " ");
}
Пример #8
0
/** Complete non-blocking connect()-sequence. Check access and
 * terminate connection, if trouble detected.
 * @param cptr Client to which we have connected, with all ConfItem structs attached.
 * @return Zero on failure (caller should exit_client()), non-zero on success.
 */
static int completed_connection(struct Client* cptr)
{
  struct ConfItem *aconf;
  time_t newts;
  struct Client *acptr;
  int i;

  assert(0 != cptr);

  /*
   * get the socket status from the fd first to check if
   * connection actually succeeded
   */
  if ((cli_error(cptr) = os_get_sockerr(cli_fd(cptr)))) {
    const char* msg = strerror(cli_error(cptr));
    if (!msg)
      msg = "Unknown error";
    sendto_opmask_butone(0, SNO_OLDSNO, "Connection failed to %s: %s",
                         cli_name(cptr), msg);
    return 0;
  }
  if (!(aconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_SERVER))) {
    sendto_opmask_butone(0, SNO_OLDSNO, "Lost Server Line for %s", cli_name(cptr));
    return 0;
  }
  if (s_state(&(cli_socket(cptr))) == SS_CONNECTING)
    socket_state(&(cli_socket(cptr)), SS_CONNECTED);

  if (!EmptyString(aconf->passwd))
    sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd);

  /*
   * Create a unique timestamp
   */
  newts = TStime();
  for (i = HighestFd; i > -1; --i) {
    if ((acptr = LocalClientArray[i]) && 
        (IsServer(acptr) || IsHandshake(acptr))) {
      if (cli_serv(acptr)->timestamp >= newts)
        newts = cli_serv(acptr)->timestamp + 1;
    }
  }
  assert(0 != cli_serv(cptr));

  cli_serv(cptr)->timestamp = newts;
  SetHandshake(cptr);
  /*
   * Make us timeout after twice the timeout for DNS look ups
   */
  cli_lasttime(cptr) = CurrentTime;
  ClearPingSent(cptr);

  sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6n :%s",
                cli_name(&me), cli_serv(&me)->timestamp, newts,
		MAJOR_PROTOCOL, NumServCap(&me),
		feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me));

  return (IsDead(cptr)) ? 0 : 1;
}
Пример #9
0
/** Remove a client from a server's user array.
 * @param[in] server %Server that owns the user to remove.
 * @param[in] yxx Numnick of client to remove.
 */
void RemoveYXXClient(struct Client* server, const char* yxx)
{
    assert(0 != server);
    assert(0 != yxx);
    if (*yxx) {
        Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx,
               base64toint(yxx) & cli_serv(server)->nn_mask));
        cli_serv(server)->client_list[base64toint(yxx) & cli_serv(server)->nn_mask] = 0;
    }
}
Пример #10
0
/**
 * Send a (prefixed) command to all servers matching or not matching a
 * flag but one.
 * @param[in] from Client sending the command.
 * @param[in] cmd Long name of command (ignored).
 * @param[in] tok Short name of command.
 * @param[in] one Client direction to skip (or NULL).
 * @param[in] require Only send to servers with this Flag bit set.
 * @param[in] forbid Do not send to servers with this Flag bit set.
 * @param[in] pattern Format string for command arguments.
 */
void sendcmdto_flag_serv_butone(struct Client *from, const char *cmd,
                                const char *tok, struct Client *one,
                                int require, int forbid,
                                const char *pattern, ...)
{
  struct VarData vd;
  struct MsgBuf *mb;
  struct DLink *lp;

  vd.vd_format = pattern; /* set up the struct VarData for %v */
  va_start(vd.vd_args, pattern);

  /* use token */
  mb = msgq_make(&me, "%C %s %v", from, tok, &vd);
  va_end(vd.vd_args);

  /* send it to our downlinks */
  for (lp = cli_serv(&me)->down; lp; lp = lp->next) {
    if (one && lp->value.cptr == cli_from(one))
      continue;
    if ((require < FLAG_LAST_FLAG) && !HasFlag(lp->value.cptr, require))
      continue;
    if ((forbid < FLAG_LAST_FLAG) && HasFlag(lp->value.cptr, forbid))
      continue;
    send_buffer(lp->value.cptr, mb, 0);
  }

  msgq_clean(mb);
}
Пример #11
0
/**
 * Send a (prefixed) command to all servers but one.
 * @param[in] from Client sending the command.
 * @param[in] cmd Long name of command (ignored).
 * @param[in] tok Short name of command.
 * @param[in] one Client direction to skip (or NULL).
 * @param[in] pattern Format string for command arguments.
 */
void sendcmdto_serv(struct Client *from, const char *cmd,
                    const char *tok, struct Client *one,
                    const char *pattern, ...)
{
  struct VarData vd;
  struct MsgBuf *mb;
  struct DLink *lp;

  vd.vd_format = pattern; /* set up the struct VarData for %v */
  va_start(vd.vd_args, pattern);

  /* use token */
  mb = msgq_make(&me, "%C %s %v", from, tok, &vd);
  va_end(vd.vd_args);

  /* canonicalize 'one' pointer */
  if (one)
    one = cli_from(one);

  /* send it to our downlinks */
  for (lp = cli_serv(&me)->down; lp; lp = lp->next) {
    if (lp->value.cptr == one)
      continue;
    send_buffer(lp->value.cptr, mb, 0);
  }

  msgq_clean(mb);
}
Пример #12
0
/*
 *  mo_squit (oper)
 *
 *    parv[0] = sender prefix
 *    parv[1] = server name
 *    parv[2] = comment (optional)
 *
 */
int mo_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  const char* server;
  struct Client *acptr;
  struct Client *acptr2;
  char *comment;
      
  if (parc < 2) 
    return need_more_params(sptr, "SQUIT");

  if (parc < 3 || BadPtr(parv[2]))
    comment = cli_name(sptr);
  else
    comment = parv[2];

  server = parv[1];
  /*
   * The following allows wild cards in SQUIT. Only useful
   * when the command is issued by an oper.
   */
  for (acptr = GlobalClientList; (acptr = next_client(acptr, server));
      acptr = cli_next(acptr)) {
    if (IsServer(acptr) || IsMe(acptr))
      break;
  }
  
  /* Not found? Bugger. */
  if (!acptr || IsMe(acptr))
    return send_reply(sptr, ERR_NOSUCHSERVER, server);

  /*
   * Look for a matching server that is closer,
   * that way we won't accidentally squit two close
   * servers like davis.* and davis-r.* when typing
   * /SQUIT davis*
   */
  for (acptr2 = cli_serv(acptr)->up; acptr2 != &me;
      acptr2 = cli_serv(acptr2)->up)
    if (!match(server, cli_name(acptr2)))
      acptr = acptr2;
  
  /* Disallow local opers to squit remote servers */
  if (IsLocOp(sptr) && !MyConnect(acptr))
    return send_reply(sptr, ERR_NOPRIVILEGES);

  return exit_client(cptr, acptr, sptr, comment);
}
Пример #13
0
/** Set a server's numeric nick.
 * @param[in] cptr %Client that announced the server (ignored).
 * @param[in,out] server %Server that is being assigned a numnick.
 * @param[in] yxx %Numeric nickname for server.
 */
void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
{
    unsigned int index;
    if (5 == strlen(yxx)) {
        ircd_strncpy(cli_yxx(server), yxx, 2);
        ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3);
    }
    else {
        (cli_yxx(server))[0]               = yxx[0];
        cli_serv(server)->nn_capacity[0] = yxx[1];
        cli_serv(server)->nn_capacity[1] = yxx[2];
    }
    cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity);

    index = base64toint(cli_yxx(server));
    if (index >= lastNNServer)
        lastNNServer = index + 1;
    server_list[index] = server;

    /* Note, exit_one_client uses the fact that `client_list' != NULL to
     * determine that SetServerYXX has been called - and then calls
     * ClearServerYXX. However, freeing the allocation happens in free_client() */
    cli_serv(server)->client_list =
        (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*));
}
Пример #14
0
/** Attach CONF_UWORLD items to a server and everything attached to it. */
static void
attach_conf_uworld(struct Client *cptr)
{
  struct DLink *lp;

  attach_confs_byhost(cptr, cli_name(cptr), CONF_UWORLD);
  for (lp = cli_serv(cptr)->down; lp; lp = lp->next)
    attach_conf_uworld(lp->value.cptr);
}
Пример #15
0
/*
 * ms_pong - server message handler
 *
 * parv[0] = sender prefix
 * parv[1] = origin
 * parv[2] = destination
 */
int ms_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char*          origin;
  char*          destination;
  assert(0 != cptr);
  assert(0 != sptr);
  assert(IsServer(cptr));

  if (parc < 2 || EmptyString(parv[1])) {
    return protocol_violation(sptr,"No Origin on PONG");
  }
  origin      = parv[1];
  destination = parv[2];
  ClearPingSent(cptr);
  ClearPingSent(sptr);
  cli_lasttime(cptr) = CurrentTime;

  if (parc > 5)
  {
    /* AsLL pong */
    cli_serv(cptr)->asll_rtt = atoi(militime_float(parv[3]));
    cli_serv(cptr)->asll_to = atoi(parv[4]);
    cli_serv(cptr)->asll_from = atoi(militime_float(parv[5]));
    cli_serv(cptr)->asll_last = CurrentTime;
    return 0;
  }
  
  if (EmptyString(destination))
    return 0;
  
  if (*destination == '!')
  {
    /* AsLL ping reply from a non-AsLL server */
    cli_serv(cptr)->asll_rtt = atoi(militime_float(destination + 1));
  }
  else if (0 != ircd_strcmp(destination, cli_name(&me)))
  {
    struct Client* acptr;
    if ((acptr = FindClient(destination)))
      sendcmdto_one(sptr, CMD_PONG, acptr, "%s %s", origin, destination);
  }
  return 0;
}
Пример #16
0
/** Allocate a new Server object for a client.
 * If Client::cli_serv == NULL, allocate a Server structure for it and
 * initialize it.
 * @param[in] cptr %Client to make into a server.
 * @return The value of cli_serv(\a cptr).
 */
struct Server *make_server(struct Client *cptr)
{
  struct Server *serv = cli_serv(cptr);

  assert(cli_verify(cptr));

  if (!serv)
  {
    serv = (struct Server*) MyMalloc(sizeof(struct Server));
    assert(0 != serv);
    memset(serv, 0, sizeof(struct Server)); /* All variables are 0 by default */
    servs.inuse++;
    servs.alloc++;
    cli_serv(cptr) = serv;
    cli_serv(cptr)->lag = 60000;
    *serv->by = '\0';
    DupString(serv->last_error_msg, "<>");      /* String must be non-empty */
  }
  return cli_serv(cptr);
}
Пример #17
0
/*
 * m_links - generic message handler
 *
 * parv[0] = sender prefix
 * parv[1] = servername mask
 *
 * or
 *
 * parv[0] = sender prefix
 * parv[1] = server to query
 * parv[2] = servername mask
 */
int m_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char *mask;
  struct Client *acptr;

  if (feature_bool(FEAT_HIS_LINKS) && !IsAnOper(sptr))
  {
    send_reply(sptr, RPL_ENDOFLINKS, parc < 2 ? "*" : parv[1]);
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr,
                  "/LINKS has been disabled, from CFV-165.  Visit ", 
                  feature_str(FEAT_HIS_URLSERVERS));
    return 0;
  }

  if (parc > 2)
  {
    if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) !=
        HUNTED_ISME)
      return 0;
    mask = parv[2];
  }
  else
    mask = parc < 2 ? 0 : parv[1];

  for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr))
  {
    if (!IsServer(acptr) && !IsMe(acptr))
      continue;
    if (!BadPtr(mask) && match(mask, cli_name(acptr)))
      continue;
    send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up),
        cli_hopcount(acptr), cli_serv(acptr)->prot,
        ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)"));
  }

  send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask);

  return 0;
}
Пример #18
0
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));
  }
}
Пример #19
0
/** 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] = '-';
}
Пример #20
0
/*
 * Taken the code from ExitOneClient() for this and placed it here.
 * - avalon
 */
void remove_client_from_list(struct Client *cptr)
{
  assert(cli_verify(cptr));
  assert(con_verify(cli_connect(cptr)));
  assert(!cli_prev(cptr) || cli_verify(cli_prev(cptr)));
  assert(!cli_next(cptr) || cli_verify(cli_next(cptr)));
  assert(!IsMe(cptr));

  /* Only remove from the list if it actually IS in the list.
   * cli_next(cptr) cannot be NULL here if cptr is in the list,
   * only &me is at the end, and we never try to remove &me  -GW 
   */ 
  if(cli_next(cptr))
  {
    if (cli_prev(cptr))
      cli_next(cli_prev(cptr)) = cli_next(cptr);
    else {
      GlobalClientList = cli_next(cptr);
      cli_prev(GlobalClientList) = 0;
    }
    cli_prev(cli_next(cptr)) = cli_prev(cptr);
  }
  cli_next(cptr) = cli_prev(cptr) = 0;

  if (IsUser(cptr) && cli_user(cptr)) {
    add_history(cptr, 0);
    off_history(cptr);
  }
  if (cli_user(cptr)) {
    free_user(cli_user(cptr));
    cli_user(cptr) = 0;
  }

  if (cli_serv(cptr)) {
    if (cli_serv(cptr)->user) {
      free_user(cli_serv(cptr)->user);
      cli_serv(cptr)->user = 0;
    }
    if (cli_serv(cptr)->client_list)
      MyFree(cli_serv(cptr)->client_list);
    MyFree(cli_serv(cptr)->last_error_msg);
    MyFree(cli_serv(cptr));
#ifdef  DEBUGMODE
    --servs.inuse;
#endif
  }
  free_client(cptr);
}
Пример #21
0
/** Update server start timestamps and TS offsets.
 * @param[in] cptr Server that just connected.
 * @param[in] timestamp Current time according to \a cptr.
 * @param[in] start_timestamp Time that \a cptr started.
 * @param[in] recv_time Current time as we know it.
 */
static void
check_start_timestamp(struct Client *cptr, time_t timestamp, time_t start_timestamp, time_t recv_time)
{
  Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
         cli_serv(&me)->timestamp, start_timestamp));
  Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
         "difference %ld", recv_time, timestamp, timestamp - recv_time));
  if (feature_bool(FEAT_RELIABLE_CLOCK)) {
    if (start_timestamp < cli_serv(&me)->timestamp)
      cli_serv(&me)->timestamp = start_timestamp;
    if (IsUnknown(cptr))
      cli_serv(cptr)->timestamp = TStime();
  } else if (start_timestamp < cli_serv(&me)->timestamp) {
    sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
                         "%Tu < %Tu", start_timestamp,
                         cli_serv(&me)->timestamp);
    cli_serv(&me)->timestamp = start_timestamp;
    TSoffset += timestamp - recv_time;
    sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
                         (int)(timestamp - recv_time));
  } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
             IsUnknown(cptr)) {
    cli_serv(cptr)->timestamp = TStime();
  } else if (timestamp != recv_time) {
    /*
     * Equal start times, we have a collision.  Let the connected-to
     * server decide. This assumes leafs issue more than half of the
     * connection attempts.
     */
    if (IsUnknown(cptr))
      cli_serv(cptr)->timestamp = TStime();
    else if (IsHandshake(cptr)) {
      sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
                           (int)(timestamp - recv_time));
      TSoffset += timestamp - recv_time;
    }
  }
}
Пример #22
0
/*
 * ms_asll - server message handler
 */
int ms_asll(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char *mask;
  struct Client *acptr;
  int hits;
  int i;

  if (parc < 2)
    return need_more_params(sptr, "ASLL");

  if (parc > 5) {
    if (!(acptr = findNUser(parv[1])))
      return 0;
    if (MyUser(acptr))
      send_asll_reply(sptr, acptr, parv[2], atoi(parv[3]), atoi(parv[4]), atoi(parv[5]));
    else
      sendcmdto_prio_one(sptr, CMD_ASLL, acptr, "%C %s %s %s %s",
        acptr, parv[2], parv[3], parv[4], parv[5]);
    return 0;
  }

  if (hunt_server_prio_cmd(sptr, CMD_ASLL, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME)
    return 0;
  mask = parv[1];

  for (i = hits = 0; i <= HighestFd; i++) {
    acptr = LocalClientArray[i];
    if (!acptr || !IsServer(acptr) || !MyConnect(acptr) || match(mask, cli_name(acptr)))
      continue;
    sendcmdto_prio_one(&me, CMD_ASLL, sptr, "%C %s %i %i %i", sptr,
      cli_name(acptr), cli_serv(acptr)->asll_rtt,
      cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from);
    hits++;
  }
  sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :AsLL for %s: %d local servers matched", sptr, mask, hits);
  return 0;
}
Пример #23
0
/** Remove \a cptr from lists that it is a member of.
 * Specifically, this delinks \a cptr from #GlobalClientList, updates
 * the whowas history list, frees its Client::cli_user and
 * Client::cli_serv fields, and finally calls free_client() on it.
 * @param[in] cptr Client to remove from lists and free.
 */
void remove_client_from_list(struct Client *cptr)
{
  assert(cli_verify(cptr));
  assert(con_verify(cli_connect(cptr)));
  assert(!cli_prev(cptr) || cli_verify(cli_prev(cptr)));
  assert(!cli_next(cptr) || cli_verify(cli_next(cptr)));
  assert(!IsMe(cptr));

  /* Only try remove cptr from the list if it IS in the list.
   * cli_next(cptr) cannot be NULL here, as &me is always the end
   * the list, and we never remove &me.    -GW 
   */
  if(cli_next(cptr))
  {
    if (cli_prev(cptr))
      cli_next(cli_prev(cptr)) = cli_next(cptr);
    else {
      GlobalClientList = cli_next(cptr);
      cli_prev(GlobalClientList) = 0;
    }
    cli_prev(cli_next(cptr)) = cli_prev(cptr);
  }
  cli_next(cptr) = cli_prev(cptr) = 0;

  if (IsUser(cptr) && cli_user(cptr)) {
    add_history(cptr, 0);
    off_history(cptr);
  }
  if (cli_user(cptr)) {
    free_user(cli_user(cptr));
    cli_user(cptr) = 0;
  }

  if (cli_serv(cptr)) {
    if (cli_serv(cptr)->user) {
      free_user(cli_serv(cptr)->user);
      cli_serv(cptr)->user = 0;
    }
    if (cli_serv(cptr)->client_list)
      MyFree(cli_serv(cptr)->client_list);
    MyFree(cli_serv(cptr)->last_error_msg);
    MyFree(cli_serv(cptr));
    --servs.inuse;
    --servs.alloc;
  }
  free_client(cptr);
}
Пример #24
0
/** Register numeric of new (local) client.
 * See @ref numnicks for more details.
 * Assign a numnick and add it to our client_list.
 * @param[in] cptr %User being registered.
 */
int SetLocalNumNick(struct Client *cptr)
{
    static unsigned int last_nn     = 0;
    struct Client**     client_list = cli_serv(&me)->client_list;
    unsigned int        mask        = cli_serv(&me)->nn_mask;
    unsigned int        count       = 0;

    assert(cli_user(cptr)->server == &me);

    while (client_list[last_nn & mask]) {
        if (++count == NN_MAX_CLIENT) {
            assert(count < NN_MAX_CLIENT);
            return 0;
        }
        if (++last_nn == NN_MAX_CLIENT)
            last_nn = 0;
    }
    client_list[last_nn & mask] = cptr;  /* Reserve the numeric ! */

    inttobase64(cli_yxx(cptr), last_nn, 3);
    if (++last_nn == NN_MAX_CLIENT)
        last_nn = 0;
    return 1;
}
Пример #25
0
/** Set a server's capacity.
 * @param[in] c %Server whose capacity is being set.
 * @param[in] capacity Maximum number of clients the server supports.
 */
void SetYXXCapacity(struct Client* c, unsigned int capacity)
{
    unsigned int max_clients = 16;
    /*
     * Calculate mask to be used for the maximum number of clients
     */
    while (max_clients < capacity)
        max_clients <<= 1;
    /*
     * Sanity checks
     */
    if (max_clients > NN_MAX_CLIENT) {
        fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
                "too large ! Please decrease this value.\n",
                max_clients - NN_MAX_CLIENT);
        exit(-1);
    }
    --max_clients;
    inttobase64(cli_serv(c)->nn_capacity, max_clients, 3);
    cli_serv(c)->nn_mask = max_clients;       /* Our Numeric Nick mask */
    cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1,
                               sizeof(struct Client*));
    server_list[base64toint(cli_yxx(c))] = c;
}
Пример #26
0
/*
 *  ms_squit (server)
 *
 *    parv[0] = sender prefix
 *    parv[1] = server name
 *    parv[2] = timestamp
 *    parv[parc-1] = comment
 *
 * No longer supports wildcards from servers. 
 * No longer squits a server that gave us an malformed squit message.
 *    - Isomer 1999-12-18
 * 
 */
int ms_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  const char* server = parv[1];
  struct Client *acptr;
  time_t timestamp = 0;
  char *comment = 0;
  
  if (parc < 2) 
    return need_more_params(sptr, "SQUIT");

  comment = parv[parc-1];
  
  if (BadPtr(parv[parc - 1]))
  	comment = cli_name(sptr);
  	
  acptr = FindServer(server);

  if (!acptr)
    acptr = FindNServer(server);

  if (!acptr) {
    Debug((DEBUG_NOTICE, "Ignoring SQUIT to an unknown server"));
    return 0;
  }
  
  /* If they are squitting me, we reverse it */
  if (IsMe(acptr))
    acptr = cptr; /* Bugfix by Prefect */

  if (parc > 2)
    timestamp = atoi(parv[2]);
  else
    protocol_violation(cptr, "SQUIT with no timestamp/reason");

  /* If atoi(parv[2]) == 0 we must indeed squit !
   * It will be our neighbour.
   */
  if ( timestamp != 0 && timestamp != cli_serv(acptr)->timestamp)
  {
    Debug((DEBUG_NOTICE, "Ignoring SQUIT with the wrong timestamp"));
    return 0;
  }
  
  return exit_client(cptr, acptr, sptr, comment);
}
Пример #27
0
/** Look up a user by numnick string.
 * See @ref numnicks for more details.
 * @param[in] yxx %Numeric nickname of user.
 * @return %User with that numnick (or NULL).
 */
struct Client* findNUser(const char* yxx)
{
    struct Client* server = 0;
    if (5 == strlen(yxx)) {
        if (0 != (server = FindXNServer(yxx))) {
            Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx,
                   base64toint(yxx + 2) & cli_serv(server)->nn_mask));
            return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask];
        }
    }
    else if (0 != (server = FindNServer(yxx))) {
        Debug((DEBUG_DEBUG, "findNUser: %s(%d)",
               yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask));
        return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask];
    }
    return 0;
}
Пример #28
0
/** Close the connection with the highest sendq.
 * This should be called when we need to free buffer memory.
 * @param[in] servers_too If non-zero, consider killing servers, too.
 */
void
kill_highest_sendq(int servers_too)
{
  int i;
  unsigned int highest_sendq = 0;
  struct Client *highest_client = 0;

  for (i = HighestFd; i >= 0; i--)
  {
    if (!LocalClientArray[i] || (!servers_too && cli_serv(LocalClientArray[i])))
      continue; /* skip servers */
    
    /* If this sendq is higher than one we last saw, remember it */
    if (MsgQLength(&(cli_sendQ(LocalClientArray[i]))) > highest_sendq)
    {
      highest_client = LocalClientArray[i];
      highest_sendq = MsgQLength(&(cli_sendQ(highest_client)));
    }
  }

  if (highest_client)
    dead_link(highest_client, "Buffer allocation error");
}
Пример #29
0
/** Handle a CREATE message from a server.
 * Atomically creates a new channel and ops the creator.
 *
 * \a parv has the following elements:
 * \li \a parv[1] Comma-separated list of channels to create.
 * \li \a parv[2] Creation timestamp for the channel(s).
 *
 * See @ref m_functions for discussion of the arguments.
 * @param[in] cptr Client that sent us the message.
 * @param[in] sptr Original source of message.
 * @param[in] parc Number of arguments.
 * @param[in] parv Argument vector.
 */
int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  time_t chanTS; /* channel creation time */
  char *p; /* strtok state */
  char *name; /* channel name */
  struct Channel *chptr; /* channel */
  struct JoinBuf join; /* join and create buffers */
  struct JoinBuf create;
  struct ModeBuf mbuf; /* a mode buffer */
  int badop; /* a flag */

  if (IsServer(sptr))
    return protocol_violation(sptr,"%s tried to CREATE a channel", cli_name(sptr));

  /* sanity checks: Only accept CREATE messages from servers */
  if (parc < 3 || *parv[2] == '\0')
    return need_more_params(sptr,"CREATE");

  chanTS = atoi(parv[2]);

  /* A create that didn't appear during a burst has that servers idea of
   * the current time.  Use it for lag calculations.
   */
  if (!IsBurstOrBurstAck(sptr) && 0 != chanTS)
    cli_serv(cli_user(sptr)->server)->lag = TStime() - chanTS;

  /* If this server is >1 minute fast, warn */
  if (TStime() - chanTS<-60)
  {
    static time_t rate;
    sendto_opmask_ratelimited(0, SNO_NETWORK, &rate,
                              "Timestamp drift from %C (%is); issuing "
                              "SETTIME to correct this",
                              cli_user(sptr)->server,
                              chanTS - TStime());
    /* Now issue a SETTIME to resync.  If we're in the wrong, our
     * (RELIABLE_CLOCK) hub will bounce a SETTIME back to us.
     */
    sendcmdto_prio_one(&me, CMD_SETTIME, cli_user(sptr)->server,
                       "%Tu %C", TStime(), cli_user(sptr)->server);
  }

  joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
  joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, chanTS);

  /* For each channel in the comma separated list: */
  for (name = ircd_strtok(&p, parv[1], ","); name;
       name = ircd_strtok(&p, 0, ",")) {
    badop = 0;

    if (IsLocalChannel(name))
      continue;

    if ((chptr = FindChannel(name)))
    {
      /* Is the remote server confused? */
      if (find_member_link(chptr, sptr)) {
        protocol_violation(sptr, "%s tried to CREATE a channel already joined", cli_name(sptr));
        continue;
      }

      /* Check if we need to bounce a mode */
      if (TStime() - chanTS > TS_LAG_TIME ||
	  (chptr->creationtime && chanTS > chptr->creationtime &&
	   /* Accept CREATE for zannels. This is only really necessary on a network
	      with servers prior to 2.10.12.02: we just accept their TS and ignore
	      the fact that it was a zannel. The influence of this on a network
	      that is completely 2.10.12.03 or higher is neglectable: Normally
	      a server only sends a CREATE after first sending a DESTRUCT. Thus,
	      by receiving a CREATE for a zannel one of three things happened:
	      1. The DESTRUCT was sent during a net.break; this could mean that
	         our zannel is at the verge of expiring too, it should have been
		 destructed. It is correct to copy the newer TS now, all modes
		 already have been reset, so it will be as if it was destructed
		 and immediately recreated. In order to avoid desyncs of modes,
		 we don't accept a CREATE for channels that have +A set.
	      2. The DESTRUCT passed, then someone created the channel on our
	         side and left it again. In this situation we have a near
		 simultaneous creation on two servers; the person on our side
		 already left within the time span of a message propagation.
		 The channel will therefore be less than 48 hours old and no
		 'protection' is necessary.
              3. The source server sent the CREATE while linking,
                 before it got the BURST for our zannel.  If this
                 happens, we should reset the channel back to the old
                 timestamp.  This can be distinguished from case #1 by
                 checking IsBurstOrBurstAck(cli_user(sptr)->server).
	    */
#if defined(UNDERNET)
	   !(chptr->users == 0 && !chptr->mode.apass[0]))) {
#else
          !(chptr->users == 0))) {
#endif
        if (!IsBurstOrBurstAck(cli_user(sptr)->server)) {
          modebuf_init(&mbuf, sptr, cptr, chptr,
                       (MODEBUF_DEST_SERVER |  /* Send mode to server */
                        MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
                        MODEBUF_DEST_BOUNCE)); /* And bounce the mode */

#if defined(UNDERNET)
          modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, MAXOPLEVEL + 1);
#else
          modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, 0);
#endif

          modebuf_flush(&mbuf);

          badop = 1;
        } else if (chanTS > chptr->creationtime + 4) {
          /* If their handling of the BURST will lead to deopping the
           * user, have the user join without getting ops (if the
           * server's handling of the BURST keeps their ops, the channel
           * will use our timestamp).
           */
          badop = 1;
        }

        if (badop)
          joinbuf_join(&join, chptr, 0);
      }
    }
    else /* Channel doesn't exist: create it */
      chptr = get_channel(sptr, name, CGT_CREATE);

    if (!badop) {
      /* Set (or correct) our copy of the TS */
      chptr->creationtime = chanTS;
      joinbuf_join(&create, chptr, CHFL_CHANOP);
    }
  }
Пример #30
0
/** Send a (prefixed) WALL of type \a type to all users except \a one.
 * @warning \a pattern must not contain %v.
 * @param[in] from Source of the command.
 * @param[in] type One of WALL_DESYNCH, WALL_WALLOPS or WALL_WALLUSERS.
 * @param[in] one Client direction to skip (or NULL).
 * @param[in] pattern Format string for command arguments.
 */
void sendwallto_group_butone(struct Client *from, int type, struct Client *one,
			     const char *pattern, ...)
{
  struct VarData vd;
  struct Client *cptr;
  struct MsgBuf *mb;
  struct DLink *lp;
  char *prefix=NULL;
  char *tok=NULL;
  int his_wallops;
  int i;

  vd.vd_format = pattern;

  /* Build buffer to send to users */
  va_start(vd.vd_args, pattern);
  switch (type) {
    	case WALL_DESYNCH:
	  	prefix="";
		tok=TOK_DESYNCH;
		break;
    	case WALL_WALLOPS:
	  	prefix="* ";
		tok=TOK_WALLOPS;
		break;
    	case WALL_WALLUSERS:
	  	prefix="$ ";
		tok=TOK_WALLUSERS;
		break;
	default:
		assert(0);
  }
  mb = msgq_make(0, "%:#C " MSG_WALLOPS " :%s%v", from, prefix,&vd);
  va_end(vd.vd_args);

  /* send buffer along! */
  his_wallops = feature_bool(FEAT_HIS_WALLOPS);
  for (i = 0; i <= HighestFd; i++)
  {
    if (!(cptr = LocalClientArray[i]) ||
	(cli_fd(cli_from(cptr)) < 0) ||
	(type == WALL_DESYNCH && !SendDebug(cptr)) ||
	(type == WALL_WALLOPS &&
         (!SendWallops(cptr) || (his_wallops && !IsAnOper(cptr)))) ||
        (type == WALL_WALLUSERS && !SendWallops(cptr)))
      continue; /* skip it */
    send_buffer(cptr, mb, 1);
  }

  msgq_clean(mb);

  /* Build buffer to send to servers */
  va_start(vd.vd_args, pattern);
  mb = msgq_make(&me, "%C %s :%v", from, tok, &vd);
  va_end(vd.vd_args);

  /* send buffer along! */
  for (lp = cli_serv(&me)->down; lp; lp = lp->next) {
    if (one && lp->value.cptr == cli_from(one))
      continue;
    send_buffer(lp->value.cptr, mb, 1);
  }

  msgq_clean(mb);
}