Ejemplo n.º 1
0
/** Find the first (best) Client block to attach.
 * @param cptr Client for whom to check rules.
 * @return Authorization check result.
 */
enum AuthorizationCheckResult attach_iline(struct Client* cptr)
{
  struct ConfItem* aconf;

  assert(0 != cptr);

  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
    if (aconf->status != CONF_CLIENT)
      continue;
    /* If you change any of this logic, please make corresponding
     * changes in conf_debug_iline() below.
     */
    if (aconf->address.port && aconf->address.port != cli_listener(cptr)->addr.port)
      continue;
    if (aconf->username && match(aconf->username, cli_username(cptr)))
      continue;
    if (aconf->host && match(aconf->host, cli_sockhost(cptr)))
      continue;
    if (aconf->countrymask && match(aconf->countrymask, cli_countrycode(cptr)))
      continue;
    if (aconf->continentmask && match(aconf->continentmask, cli_continentcode(cptr)))
      continue;
    if ((aconf->addrbits >= 0)
        && !ipmask_check(&cli_ip(cptr), &aconf->address.addr, aconf->addrbits))
      continue;
    if (IPcheck_nr(cptr) > aconf->maximum)
      return ACR_TOO_MANY_FROM_IP;
    if (aconf->redirserver && !EmptyString(aconf->redirserver)) {
      send_reply(cptr, RPL_BOUNCE, aconf->redirserver, aconf->redirport);
      return ACR_NO_AUTHORIZATION;
    }
    if (aconf->username && !IsWebIRCUserIdent(cptr) && (aconf->flags & CONF_NOIDENTTILDE))
      SetFlag(cptr, FLAG_DOID);
    return attach_conf(cptr, aconf);
  }
  return ACR_NO_AUTHORIZATION;
}
Ejemplo n.º 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, " ");
}
Ejemplo n.º 3
0
void add_connection(struct Listener* listener, int fd, void *ssl) {
#else
void add_connection(struct Listener* listener, int fd) {
#endif
  struct irc_sockaddr addr;
  struct Client      *new_client;
  time_t             next_target = 0;
#if defined(USE_SSL)
  char *sslfp;
#endif

  const char* const throttle_message =
         "ERROR :Your host is trying to (re)connect too fast -- throttled\r\n";
       /* 12345678901234567890123456789012345679012345678901234567890123456 */
  const char* const register_message =
         "ERROR :Unable to complete your registration\r\n";

  assert(0 != listener);

  /*
   * Removed preliminary access check. Full check is performed in m_server and
   * m_user instead. Also connection time out help to get rid of unwanted
   * connections.
   */
  if (!os_get_peername(fd, &addr) || !os_set_nonblocking(fd)) {
    ++ServerStats->is_ref;
#if defined(USE_SSL)
    ssl_murder(ssl, fd, NULL);
#else
    close(fd);
#endif
    return;
  }
  /*
   * Disable IP (*not* TCP) options.  In particular, this makes it impossible
   * to use source routing to connect to the server.  If we didn't do this
   * (and if intermediate networks didn't drop source-routed packets), an
   * attacker could successfully IP spoof us...and even return the anti-spoof
   * ping, because the options would cause the packet to be routed back to
   * the spoofer's machine.  When we disable the IP options, we delete the
   * source route, and the normal routing takes over.
   */
  os_disable_options(fd);

  if (listener_server(listener))
  {
    new_client = make_client(0, STAT_UNKNOWN_SERVER);
  }
  else
  {
    /*
     * Add this local client to the IPcheck registry.
     *
     * If they're throttled, murder them, but tell them why first.
     */
    if (!IPcheck_local_connect(&addr.addr, &next_target))
    {
      ++ServerStats->is_ref;
#if defined(USE_SSL)
      ssl_murder(ssl, fd, throttle_message);
#else
      write(fd, throttle_message, strlen(throttle_message));
      close(fd);
#endif
      return;
    }
    new_client = make_client(0, STAT_UNKNOWN_USER);
    SetIPChecked(new_client);
  }

  /*
   * Copy ascii address to 'sockhost' just in case. Then we have something
   * valid to put into error messages...
   */
  ircd_ntoa_r(cli_sock_ip(new_client), &addr.addr);
  strcpy(cli_sockhost(new_client), cli_sock_ip(new_client));
  memcpy(&cli_ip(new_client), &addr.addr, sizeof(cli_ip(new_client)));

  if (next_target)
    cli_nexttarget(new_client) = next_target;

  cli_fd(new_client) = fd;
  if (!socket_add(&(cli_socket(new_client)), client_sock_callback,
		  (void*) cli_connect(new_client), SS_CONNECTED, 0, fd)) {
    ++ServerStats->is_ref;
#if defined(USE_SSL)
    ssl_murder(ssl, fd, register_message);
#else
    write(fd, register_message, strlen(register_message));
    close(fd);
#endif
    cli_fd(new_client) = -1;
    return;
  }
#if defined(USE_SSL)
  if (ssl) {
    cli_socket(new_client).s_ssl = ssl;
    sslfp = ssl_get_fingerprint(ssl);
    if (sslfp)
      ircd_strncpy(cli_sslclifp(new_client), sslfp, BUFSIZE+1);
  }
#endif
  cli_freeflag(new_client) |= FREEFLAG_SOCKET;
  cli_listener(new_client) = listener;
  ++listener->ref_count;

  Count_newunknown(UserStats);
  /* if we've made it this far we can put the client on the auth query pile */
  start_auth(new_client);
}

/** Determines whether to tell the events engine we're interested in
 * writable events.
 * @param cptr Client for which to decide this.
 */
void update_write(struct Client* cptr)
{
  /* If there are messages that need to be sent along, or if the client
   * is in the middle of a /list, then we need to tell the engine that
   * we're interested in writable events--otherwise, we need to drop
   * that interest.
   */
  socket_events(&(cli_socket(cptr)),
		((MsgQLength(&cli_sendQ(cptr)) || cli_listing(cptr)) ?
		 SOCK_ACTION_ADD : SOCK_ACTION_DEL) | SOCK_EVENT_WRITABLE);
}
Ejemplo n.º 4
0
/** Attempt to send a sequence of bytes to the connection.
 * As a side effect, updates \a cptr's FLAG_BLOCKED setting
 * and sendB/sendK fields.
 * @param cptr Client that should receive data.
 * @param buf Message buffer to send to client.
 * @return Negative on connection-fatal error; otherwise
 *  number of bytes sent.
 */
unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf)
{
  unsigned int bytes_written = 0;
  unsigned int bytes_count = 0;
  assert(0 != cptr);

#if defined(USE_SSL)
  switch (client_sendv(cptr, buf, &bytes_count, &bytes_written)) {
#else
  switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written)) {
#endif
  case IO_SUCCESS:
    ClrFlag(cptr, FLAG_BLOCKED);

    cli_sendB(cptr) += bytes_written;
    cli_sendB(&me)  += bytes_written;
    /* A partial write implies that future writes will block. */
    if (bytes_written < bytes_count)
      SetFlag(cptr, FLAG_BLOCKED);
    break;
  case IO_BLOCKED:
    SetFlag(cptr, FLAG_BLOCKED);
    break;
  case IO_FAILURE:
    cli_error(cptr) = errno;
    SetFlag(cptr, FLAG_DEADSOCKET);
    break;
  }
  return bytes_written;
}

/** 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;
#if defined(USE_SSL)
  char *sslfp;
  int r;
#endif

  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(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(0, SNO_OLDSNO, "Lost Server Line for %s", cli_name(cptr));
    return 0;
  }

#if defined(USE_SSL)
  if (aconf->flags & CONF_SSL) {
    r = ssl_connect(&(cli_socket(cptr)));
    if (r == -1) {
      sendto_opmask(0, SNO_OLDSNO, "Connection failed to %s: SSL error",
                    cli_name(cptr));
      return 0;
    } else if (r == 0)
      return 1;
    sslfp = ssl_get_fingerprint(cli_socket(cptr).s_ssl);
    if (sslfp)
      ircd_strncpy(cli_sslclifp(cptr), sslfp, BUFSIZE+1);
    SetSSL(cptr);
  }
#endif

  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);

/* TODO: NEGOCIACION
  envia_config_req(cptr);
*/

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

#if defined(DDB)
  ddb_burst(cptr);
#endif

  return (IsDead(cptr)) ? 0 : 1;
}

/** Close the physical connection.  Side effects: MyConnect(cptr)
 * becomes false and cptr->from becomes NULL.
 * @param cptr Client to disconnect.
 */
void close_connection(struct Client *cptr)
{
  struct ConfItem* aconf;

  if (IsServer(cptr)) {
    ServerStats->is_sv++;
    ServerStats->is_sbs += cli_sendB(cptr);
    ServerStats->is_sbr += cli_receiveB(cptr);
    ServerStats->is_sti += CurrentTime - cli_firsttime(cptr);
    /*
     * If the connection has been up for a long amount of time, schedule
     * a 'quick' reconnect, else reset the next-connect cycle.
     */
    if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) {
      /*
       * Reschedule a faster reconnect, if this was a automatically
       * connected configuration entry. (Note that if we have had
       * a rehash in between, the status has been changed to
       * CONF_ILLEGAL). But only do this if it was a "good" link.
       */
      aconf->hold = CurrentTime;
      aconf->hold += ((aconf->hold - cli_since(cptr) >
		       feature_int(FEAT_HANGONGOODLINK)) ?
		      feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf));
/*        if (nextconnect > aconf->hold) */
/*          nextconnect = aconf->hold; */
    }
  }
  else if (IsUser(cptr)) {
    ServerStats->is_cl++;
    ServerStats->is_cbs += cli_sendB(cptr);
    ServerStats->is_cbr += cli_receiveB(cptr);
    ServerStats->is_cti += CurrentTime - cli_firsttime(cptr);
  }
  else
    ServerStats->is_ni++;

#if defined(USE_ZLIB)
  /*
   * Siempre es una conexion nuestra
   */
  if (cli_connect(cptr)->zlib_negociation & ZLIB_IN) {
    inflateEnd(cli_connect(cptr)->comp_in);
    MyFree(cli_connect(cptr)->comp_in);
  }
  if (cli_connect(cptr)->zlib_negociation & ZLIB_OUT) {
    deflateEnd(cli_connect(cptr)->comp_out);
    MyFree(cli_connect(cptr)->comp_out);
  }
#endif

  if (-1 < cli_fd(cptr)) {
    flush_connections(cptr);
    LocalClientArray[cli_fd(cptr)] = 0;
    close(cli_fd(cptr));
    socket_del(&(cli_socket(cptr))); /* queue a socket delete */
    cli_fd(cptr) = -1;
    cli_freeflag(cptr) &= ~FREEFLAG_SOCKET;
  }
  SetFlag(cptr, FLAG_DEADSOCKET);

  MsgQClear(&(cli_sendQ(cptr)));
  client_drop_sendq(cli_connect(cptr));
  DBufClear(&(cli_recvQ(cptr)));
  memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
  set_snomask(cptr, 0, SNO_SET);

  det_confs_butmask(cptr, 0);

  if (cli_listener(cptr)) {
    release_listener(cli_listener(cptr));
    cli_listener(cptr) = 0;
  }

  for ( ; HighestFd > 0; --HighestFd) {
    if (LocalClientArray[HighestFd])
      break;
  }
}

/** Close all unregistered connections.
 * @param source Oper who requested the close.
 * @return Number of closed connections.
 */
int net_close_unregistered_connections(struct Client* source)
{
  int            i;
  struct Client* cptr;
  int            count = 0;
  assert(0 != source);

  for (i = HighestFd; i > 0; --i) {
    if ((cptr = LocalClientArray[i]) && !IsRegistered(cptr)) {
      send_reply(source, RPL_CLOSING, get_client_name(source, HIDE_IP));
      exit_client(source, cptr, &me, "Oper Closing");
      ++count;
    }
  }
  return count;
}
Ejemplo n.º 5
0
/** Creates a client which has just connected to us on the given fd.
 * The sockhost field is initialized with the ip# of the host.
 * The client is not added to the linked list of clients, it is
 * passed off to the auth handler for dns and ident queries.
 * @param listener Listening socket that received the connection.
 * @param fd File descriptor of new connection.
 */
void add_connection(struct Listener* listener, int fd) {
  struct irc_sockaddr addr;
  struct Client      *new_client;
  time_t             next_target = 0;

  const char* const throttle_message =
         "ERROR :Your host is trying to (re)connect too fast -- throttled\r\n";
       /* 12345678901234567890123456789012345679012345678901234567890123456 */
  const char* const register_message =
         "ERROR :Unable to complete your registration\r\n";

  assert(0 != listener);

  /*
   * Removed preliminary access check. Full check is performed in m_server and
   * m_user instead. Also connection time out help to get rid of unwanted
   * connections.
   */
  if (!os_get_peername(fd, &addr) || !os_set_nonblocking(fd)) {
    ++ServerStats->is_ref;
    close(fd);
    return;
  }
  /*
   * Disable IP (*not* TCP) options.  In particular, this makes it impossible
   * to use source routing to connect to the server.  If we didn't do this
   * (and if intermediate networks didn't drop source-routed packets), an
   * attacker could successfully IP spoof us...and even return the anti-spoof
   * ping, because the options would cause the packet to be routed back to
   * the spoofer's machine.  When we disable the IP options, we delete the
   * source route, and the normal routing takes over.
   */
  os_disable_options(fd);

  if (listener_server(listener))
  {
    new_client = make_client(0, STAT_UNKNOWN_SERVER);
  }
  else
  {
    /*
     * Add this local client to the IPcheck registry.
     *
     * If they're throttled, murder them, but tell them why first.
     */
    if (!IPcheck_local_connect(&addr.addr, &next_target))
    {
      ++ServerStats->is_ref;
      write(fd, throttle_message, strlen(throttle_message));
      close(fd);
      return;
    }
    new_client = make_client(0, STAT_UNKNOWN_USER);
    SetIPChecked(new_client);
  }

  /*
   * Copy ascii address to 'sockhost' just in case. Then we have something
   * valid to put into error messages...
   */
  ircd_ntoa_r(cli_sock_ip(new_client), &addr.addr);
  strcpy(cli_sockhost(new_client), cli_sock_ip(new_client));
  memcpy(&cli_ip(new_client), &addr.addr, sizeof(cli_ip(new_client)));

  if (next_target)
    cli_nexttarget(new_client) = next_target;

  cli_fd(new_client) = fd;
  if (!socket_add(&(cli_socket(new_client)), client_sock_callback,
		  (void*) cli_connect(new_client), SS_CONNECTED, 0, fd)) {
    ++ServerStats->is_ref;
    write(fd, register_message, strlen(register_message));
    close(fd);
    cli_fd(new_client) = -1;
    return;
  }
  cli_freeflag(new_client) |= FREEFLAG_SOCKET;
  cli_listener(new_client) = listener;
  ++listener->ref_count;

  Count_newunknown(UserStats);
  /* if we've made it this far we can put the client on the auth query pile */
  start_auth(new_client);
}
Ejemplo n.º 6
0
/** Close the physical connection.  Side effects: MyConnect(cptr)
 * becomes false and cptr->from becomes NULL.
 * @param cptr Client to disconnect.
 */
void close_connection(struct Client *cptr)
{
  struct ConfItem* aconf;

  if (IsServer(cptr)) {
    ServerStats->is_sv++;
    ServerStats->is_sbs += cli_sendB(cptr);
    ServerStats->is_sbr += cli_receiveB(cptr);
    ServerStats->is_sti += CurrentTime - cli_firsttime(cptr);
    /*
     * If the connection has been up for a long amount of time, schedule
     * a 'quick' reconnect, else reset the next-connect cycle.
     */
    if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) {
      /*
       * Reschedule a faster reconnect, if this was a automatically
       * connected configuration entry. (Note that if we have had
       * a rehash in between, the status has been changed to
       * CONF_ILLEGAL). But only do this if it was a "good" link.
       */
      aconf->hold = CurrentTime;
      aconf->hold += ((aconf->hold - cli_since(cptr) >
		       feature_int(FEAT_HANGONGOODLINK)) ?
		      feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf));
/*        if (nextconnect > aconf->hold) */
/*          nextconnect = aconf->hold; */
    }
  }
  else if (IsUser(cptr)) {
    ServerStats->is_cl++;
    ServerStats->is_cbs += cli_sendB(cptr);
    ServerStats->is_cbr += cli_receiveB(cptr);
    ServerStats->is_cti += CurrentTime - cli_firsttime(cptr);
  }
  else
    ServerStats->is_ni++;

  if (-1 < cli_fd(cptr)) {
    flush_connections(cptr);
    LocalClientArray[cli_fd(cptr)] = 0;
    close(cli_fd(cptr));
    socket_del(&(cli_socket(cptr))); /* queue a socket delete */
    cli_fd(cptr) = -1;
  }
  SetFlag(cptr, FLAG_DEADSOCKET);

  MsgQClear(&(cli_sendQ(cptr)));
  client_drop_sendq(cli_connect(cptr));
  DBufClear(&(cli_recvQ(cptr)));
  memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
  set_snomask(cptr, 0, SNO_SET);

  det_confs_butmask(cptr, 0);

  if (cli_listener(cptr)) {
    release_listener(cli_listener(cptr));
    cli_listener(cptr) = 0;
  }

  for ( ; HighestFd > 0; --HighestFd) {
    if (LocalClientArray[HighestFd])
      break;
  }
}