Пример #1
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;
}
Пример #2
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);
    }
  }
Пример #3
0
/** Handle a SERVER message from an unregistered connection.
 *
 * \a parv has the following elements:
 * \li \a parv[1] is the server name
 * \li \a parv[2] is the hop count to the server
 * \li \a parv[3] is the start timestamp for the server
 * \li \a parv[4] is the link timestamp
 * \li \a parv[5] is the protocol version (P10 or J10)
 * \li \a parv[6] is the numnick mask for the server
 * \li \a parv[7] is a string of flags like +hs to mark hubs and services
 * \li \a parv[\a parc - 1] is the server description
 *
 * 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 mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char*            host;
  struct ConfItem* aconf;
  struct Jupe*     ajupe;
  unsigned int     hop;
  int              ret;
  unsigned short   prot;
  time_t           start_timestamp;
  time_t           timestamp;
  time_t           recv_time;
  time_t           ghost;

  if (IsUserPort(cptr))
    return exit_client_msg(cptr, cptr, &me,
                           "Cannot connect a server to a user port");

  if (parc < 8)
  {
    need_more_params(sptr, "SERVER");
    return exit_client(cptr, cptr, &me, "Need more parameters");
  }
  host = clean_servername(parv[1]);
  if (!host)
  {
    sendto_opmask(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
                  host, cli_name(cptr));
    return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
  }

  if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
    return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));

  /* check connection rules */
  if (0 != conf_eval_crule(host, CRULE_ALL)) {
    ServerStats->is_ref++;
    sendto_opmask(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
    return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
  }

  log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "SERVER: %s %s[%s]", host,
	    cli_sockhost(cptr), cli_sock_ip(cptr));

  /*
   * Detect protocol
   */
  hop = atoi(parv[2]);
  start_timestamp = atoi(parv[3]);
  timestamp = atoi(parv[4]);
  prot = parse_protocol(parv[5]);
  if (!prot)
    return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
  else if (prot < atoi(MINOR_PROTOCOL))
    return exit_new_server(cptr, sptr, host, timestamp,
                           "Incompatible protocol: %s", parv[5]);

  Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
	 host, parv[4], start_timestamp, cli_serv(&me)->timestamp));

  if (timestamp < OLDEST_TS || start_timestamp < OLDEST_TS)
    return exit_client_msg(cptr, sptr, &me,
        "Bogus timestamps (%s %s)", parv[3], parv[4]);

  /* If the server had a different name before, change it. */
  if (!EmptyString(cli_name(cptr)) &&
      (IsUnknown(cptr) || IsHandshake(cptr)) &&
      0 != ircd_strcmp(cli_name(cptr), host))
    hChangeClient(cptr, host);
  ircd_strncpy(cli_name(cptr), host, HOSTLEN);
  ircd_strncpy(cli_info(cptr), parv[parc-1][0] ? parv[parc-1] : cli_name(&me), REALLEN);
  cli_hopcount(cptr) = hop;

  if (conf_check_server(cptr)) {
    ++ServerStats->is_ref;
    sendto_opmask(0, SNO_OLDSNO, "Received unauthorized connection from %s",
                  cli_name(cptr));
    log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "Received unauthorized "
              "connection from %C [%s]", cptr,
              ircd_ntoa(&cli_ip(cptr)));
    return exit_client(cptr, cptr, &me, "No Connect block");
  }

  host = cli_name(cptr);

  update_load();

  if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
    ++ServerStats->is_ref;
    sendto_opmask(0, SNO_OLDSNO, "Access denied. No conf line for server %s",
                  cli_name(cptr));
    return exit_client_msg(cptr, cptr, &me,
                           "Access denied. No conf line for server %s", cli_name(cptr));
  }

#if defined(USE_SSL)
  if (!verify_sslclifp(cptr, aconf)) {
    ++ServerStats->is_ref;
    sendto_opmask(0, SNO_OLDSNO, "Access denied (SSL fingerprint mismatch) %s",
                  cli_name(cptr));
    return exit_client_msg(cptr, cptr, &me,
                           "No Access (SSL fingerprint mismatch) %s", cli_name(cptr));
  }
#endif

  if (*aconf->passwd && !!strcmp(aconf->passwd, cli_passwd(cptr))) {
    ++ServerStats->is_ref;
    sendto_opmask(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
                  cli_name(cptr));
    return exit_client_msg(cptr, cptr, &me,
                           "No Access (passwd mismatch) %s", cli_name(cptr));
  }

  memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));

  ret = check_loop_and_lh(cptr, sptr, &ghost, host, (parc > 7 ? parv[6] : NULL), timestamp, hop, 1);
  if (ret != 1)
    return ret;

  make_server(cptr);
  cli_serv(cptr)->timestamp = timestamp;
  cli_serv(cptr)->prot = prot;
  cli_serv(cptr)->ghost = ghost;
  memset(cli_privs(cptr), 255, sizeof(struct Privs));
  ClrPriv(cptr, PRIV_SET);
  SetServerYXX(cptr, cptr, parv[6]);
  update_uworld_flags(cptr);

  if (*parv[7] == '+')
    set_server_flags(cptr, parv[7] + 1);

  recv_time = TStime();
  check_start_timestamp(cptr, timestamp, start_timestamp, recv_time);
  ret = server_estab(cptr, aconf);

  if (feature_bool(FEAT_RELIABLE_CLOCK) &&
      abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
    sendto_opmask(0, SNO_OLDSNO, "Connected to a net with a "
                  "timestamp-clock difference of %Td seconds! "
                  "Used SETTIME to correct this.",
                  timestamp - recv_time);
    sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(),
		       cli_name(&me));
  }

  return ret;
}
Пример #4
0
/*
 * ms_settime - server message handler
 *
 * parv[0] = sender prefix
 * parv[1] = new time
 * parv[2] = server name (Only used when sptr is an Oper).
 */
int ms_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  time_t t;
  long dt;
  static char tbuf[11];
  struct DLink *lp;

  if (parc < 2) /* verify argument count */
    return need_more_params(sptr, "SETTIME");

  t = atoi(parv[1]); /* convert time and compute delta */
  dt = TStime() - t;

  /* verify value */
  if (t < OLDEST_TS || dt < -9000000)
  {
    if (IsServer(sptr)) /* protocol violation if it's from a server */
      protocol_violation(sptr, "SETTIME: Bad value (%Tu, delta %ld)", t, dt);
    else
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value (%Tu, "
                    "delta %ld)", sptr, t, dt);
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value", sptr);
    return 0;
  }

  /* reset time... */
  if (feature_bool(FEAT_RELIABLE_CLOCK))
  {
    ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime());
    parv[1] = tbuf;
  }

  if (BadPtr(parv[2])) /* spam the network */
  {
    for (lp = cli_serv(&me)->down; lp; lp = lp->next)
      if (cptr != lp->value.cptr)
        sendcmdto_prio_one(sptr, CMD_SETTIME, lp->value.cptr, "%s", parv[1]);
  }
  else
  {
    if (hunt_server_prio_cmd(sptr, CMD_SETTIME, cptr, 1, "%s %C", 2, parc,
                             parv) != HUNTED_ISME)
    {
      /* If the destination was *not* me, but I'm RELIABLE_CLOCK and the
       * delta is more than 30 seconds off, bounce back a corrected
       * SETTIME
       */
      if (feature_bool(FEAT_RELIABLE_CLOCK) && (dt > 30 || dt < -30))
        sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%s %C", parv[1], cptr);
      return 0;
    }
  }

  if (feature_bool(FEAT_RELIABLE_CLOCK))
  {
    /* don't apply settime--reliable */
    if ((dt > 600) || (dt < -600))
      sendcmdto_serv_butone(&me, CMD_DESYNCH, 0, ":Bad SETTIME from %s: %Tu "
                            "(delta %ld)", cli_name(sptr), t, dt);
    /* Let user know we're ignoring him */
    if (IsUser(sptr))
    {
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is not set %ld "
		    "seconds %s : RELIABLE_CLOCK is defined", sptr,
		    (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
    }
  }
  else /* tell opers about time change */
  {
    sendto_opmask_butone(0, SNO_OLDSNO, "SETTIME from %s, clock is set %ld "
			 "seconds %s", cli_name(sptr), (dt < 0) ? -dt : dt,
			 (dt < 0) ? "forwards" : "backwards");
    /* Apply time change... */
    TSoffset -= dt;
    /* Let the issuing user know what we did... */
    if (IsUser(sptr))
    {
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is set %ld seconds %s",
                    sptr, (dt < 0) ? -dt : dt,
                    (dt < 0) ? "forwards" : "backwards");
    }
  }

  return 0;
}
Пример #5
0
/** Check for clients that have not sent a ping response recently.
 * Reschedules itself to run again at the appropriate time.
 * @param[in] ev Timer event (ignored).
 */
static void check_pings(struct Event* ev) {
  int expire     = 0;
  int next_check = CurrentTime;
  int max_ping   = 0;
  int i;

  assert(ET_EXPIRE == ev_type(ev));
  assert(0 != ev_timer(ev));

  next_check += feature_int(FEAT_PINGFREQUENCY);
  
  /* Scan through the client table */
  for (i=0; i <= HighestFd; i++) {
    struct Client *cptr = LocalClientArray[i];
   
    if (!cptr)
      continue;
     
    assert(&me != cptr);  /* I should never be in the local client array! */
   

    /* Remove dead clients. */
    if (IsDead(cptr)) {
      exit_client(cptr, cptr, &me, cli_info(cptr));
      continue;
    }

    max_ping = IsRegistered(cptr) ? client_get_ping(cptr) :
      feature_int(FEAT_CONNECTTIMEOUT);
   
    Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d",
	   cli_name(cptr),
	   IsPingSent(cptr) ? "[Ping Sent]" : "[]", 
	   max_ping, (int)(CurrentTime - cli_lasttime(cptr))));

    /* If it's a server and we have not sent an AsLL lately, do so. */
    if (IsServer(cptr)) {
      if (CurrentTime - cli_serv(cptr)->asll_last >= max_ping) {
        char *asll_ts;

        SetPingSent(cptr);
        cli_serv(cptr)->asll_last = CurrentTime;
        expire = cli_serv(cptr)->asll_last + max_ping;
        asll_ts = militime_float(NULL);
        sendcmdto_prio_one(&me, CMD_PING, cptr, "!%s %s %s", asll_ts,
                           cli_name(cptr), asll_ts);
      }

      expire = cli_serv(cptr)->asll_last + max_ping;
      if (expire < next_check)
        next_check = expire;
    }

    /* Ok, the thing that will happen most frequently, is that someone will
     * have sent something recently.  Cover this first for speed.
     * -- 
     * If it's an unregistered client and hasn't managed to register within
     * max_ping then it's obviously having problems (broken client) or it's
     * just up to no good, so we won't skip it, even if its been sending
     * data to us. 
     * -- hikari
     */
    if ((CurrentTime-cli_lasttime(cptr) < max_ping) && IsRegistered(cptr)) {
      expire = cli_lasttime(cptr) + max_ping;
      if (expire < next_check) 
	next_check = expire;
      continue;
    }

    /* Unregistered clients pingout after max_ping seconds, they don't
     * get given a second chance - if they were then people could not quite
     * finish registration and hold resources without being subject to k/g
     * lines
     */
    if (!IsRegistered(cptr)) {
      assert(!IsServer(cptr));
      /* If client authorization time has expired, ask auth whether they
       * should be checked again later. */
      if ((CurrentTime-cli_firsttime(cptr) >= max_ping)
          && auth_ping_timeout(cptr))
        continue;
      /* OK, they still have enough time left, so we'll just skip to the
       * next client.  Set the next check to be when their time is up, if
       * that's before the currently scheduled next check -- hikari */
      expire = cli_firsttime(cptr) + max_ping;
      if (expire < next_check)
        next_check = expire;
      continue;
    }

    /* Quit the client after max_ping*2 - they should have answered by now */
    if (CurrentTime-cli_lasttime(cptr) >= (max_ping*2) )
    {
      /* If it was a server, then tell ops about it. */
      if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
        sendto_opmask_butone(0, SNO_OLDSNO,
                             "No response from %s, closing link",
                             cli_name(cptr));
      exit_client_msg(cptr, cptr, &me, "Ping timeout");
      continue;
    }
    
    if (!IsPingSent(cptr))
    {
      /* If we haven't PINGed the connection and we haven't heard from it in a
       * while, PING it to make sure it is still alive.
       */
      SetPingSent(cptr);

      /* If we're late in noticing don't hold it against them :) */
      cli_lasttime(cptr) = CurrentTime - max_ping;
      
      if (IsUser(cptr))
        sendrawto_one(cptr, MSG_PING " :%s", cli_name(&me));
      else
        sendcmdto_prio_one(&me, CMD_PING, cptr, ":%s", cli_name(&me));
    }
    
    expire = cli_lasttime(cptr) + max_ping * 2;
    if (expire < next_check)
      next_check=expire;
  }
  
  assert(next_check >= CurrentTime);
  
  Debug((DEBUG_DEBUG, "[%i] check_pings() again in %is",
	 CurrentTime, next_check-CurrentTime));
  
  timer_add(&ping_timer, check_pings, 0, TT_ABSOLUTE, next_check);
}