Ejemplo n.º 1
0
static void 
accept_connection(int pfd, void *data)
{
  static time_t      last_oper_notice = 0;

  struct irc_sockaddr sai;
  struct irc_inaddr addr;
  int                fd;
  int pe;
  struct Listener *  listener = data;

  assert(listener != NULL);
  if(listener == NULL)
    return;
  /*
   * There may be many reasons for error return, but
   * in otherwise correctly working environment the
   * probable cause is running out of file descriptors
   * (EMFILE, ENFILE or others?). The man pages for
   * accept don't seem to list these as possible,
   * although it's obvious that it may happen here.
   * Thus no specific errors are tested at this
   * point, just assume that connections cannot
   * be accepted until some old is closed first.
   */

  fd = comm_accept(listener->fd, &sai);

  copy_s_addr(IN_ADDR(addr), S_ADDR(sai));

#ifdef IPV6
  if((IN6_IS_ADDR_V4MAPPED(&IN_ADDR2(addr))) ||
  	(IN6_IS_ADDR_V4COMPAT(&IN_ADDR2(addr))))
  {
    memmove(&addr.sins.sin.s_addr, addr.sins.sin6.s6_addr+12,
            sizeof(struct in_addr));

    sai.sins.sin.sin_family = AF_INET;
  }
#endif

  if (fd < 0)
    {
      /* Re-register a new IO request for the next accept .. */
      comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
                     accept_connection, listener, 0);
      return;
    }
  /*
   * check for connection limit
   */
  if ((MAXCONNECTIONS - 10) < fd)
    {
      ++ServerStats->is_ref;
      /*
       * slow down the whining to opers bit
       */
      if((last_oper_notice + 20) <= CurrentTime)
	{
	  sendto_realops_flags(UMODE_ALL, L_ALL,"All connections in use. (%s)",
			       get_listener_name(listener));
	  last_oper_notice = CurrentTime;
	}

      send(fd, "ERROR :All connections in use\r\n", 32, 0);
      fd_close(fd);
      /* Re-register a new IO request for the next accept .. */
      comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
                     accept_connection, listener, 0);
      return;
    }

  /* Do an initial check we aren't connecting too fast or with too many
   * from this IP... */
  if ((pe = conf_connect_allowed(&addr, sai.sins.sin.sin_family)) != 0)
  {
    ServerStats->is_ref++;

    /* XXX - this can only be BANNED_CLIENT? */
    switch (pe)
    {
      case BANNED_CLIENT:
        send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0);
        break;
    }

    fd_close(fd);

    /* Re-register a new IO request for the next accept .. */
    comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
                   accept_connection, listener, 0);
    return;
  }

  ServerStats->is_ac++;

  add_connection(listener, fd);

  /* Re-register a new IO request for the next accept .. */
  comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
    accept_connection, listener, 0);
}
Ejemplo n.º 2
0
static void
accept_connection(int pfd, void *data)
{
	static time_t last_oper_notice = 0;

	struct irc_sockaddr_storage sai;
	socklen_t addrlen = sizeof(sai);
	int fd;
	struct Listener *listener = data;
	struct ConfItem *aconf;
	char buf[BUFSIZE];

	s_assert(listener != NULL);
	if(listener == NULL)
		return;


	for(;;)			/* loop until something breaks us out */
	{

		/*
		 * There may be many reasons for error return, but
		 * in otherwise correctly working environment the
		 * probable cause is running out of file descriptors
		 * (EMFILE, ENFILE or others?). The man pages for
		 * accept don't seem to list these as possible,
		 * although it's obvious that it may happen here.
		 * Thus no specific errors are tested at this
		 * point, just assume that connections cannot
		 * be accepted until some old is closed first.
		 */

		fd = comm_accept(listener->fd, (struct sockaddr *) &sai, &addrlen);

		/* This needs to be done here, otherwise we break dlines */
		mangle_mapped_sockaddr((struct sockaddr *) &sai);

		if(fd < 0)
		{
			/* Re-register a new IO request for the next accept .. */
			comm_setselect(listener->fd, FDLIST_SERVICE,
				       COMM_SELECT_READ, accept_connection, listener);
			return;
		}
		/*
		 * check for connection limit
		 */
		if((maxconnections - 10) < fd)
		{
			++ServerStats->is_ref;
			/*
			 * slow down the whining to opers bit
			 */
			if((last_oper_notice + 20) <= CurrentTime)
			{
				sendto_realops_flags(UMODE_ALL, L_ALL,
						     "All connections in use. (%s)",
						     get_listener_name(listener));
				last_oper_notice = CurrentTime;
			}

			write(fd, "ERROR :All connections in use\r\n", 32);
			comm_close(fd);
			/* Re-register a new IO request for the next accept .. */
			comm_setselect(listener->fd, FDLIST_SERVICE,
				       COMM_SELECT_READ, accept_connection, listener);
			return;
		}

		/* Do an initial check we aren't connecting too fast or with too many
		 * from this IP... */
		if((aconf = conf_connect_allowed((struct sockaddr *) &sai, sai.ss_family)) != NULL)
		{
			ServerStats->is_ref++;

			if(ConfigFileEntry.dline_with_reason)
			{
				if(ircsnprintf
				   (buf, sizeof(buf), "ERROR :*** Banned: %s\r\n",
				    aconf->passwd) >= (sizeof(buf) - 1))
				{
					buf[sizeof(buf) - 3] = '\r';
					buf[sizeof(buf) - 2] = '\n';
					buf[sizeof(buf) - 1] = '\0';
				}
			}
			else
				ircsprintf(buf, "ERROR :You have been D-lined.\r\n");

			write(fd, buf, strlen(buf));
			comm_close(fd);

			/* Re-register a new IO request for the next accept .. */
			comm_setselect(listener->fd, FDLIST_SERVICE,
				       COMM_SELECT_READ, accept_connection, listener);
			return;
		}

		ServerStats->is_ac++;
		add_connection(listener, fd, (struct sockaddr *) &sai);

	}
	/* Re-register a new IO request for the next accept .. */
	comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
		       accept_connection, listener);
}
Ejemplo n.º 3
0
void accept_connection(struct Listener* listener)
{
  static time_t      last_oper_notice = 0;
  struct SOCKADDR_IN addr;
  socklen_t          addrlen = sizeof(struct SOCKADDR_IN);
  int                fd;

  assert(0 != listener);

  listener->last_accept = CurrentTime;
  /*
   * There may be many reasons for error return, but
   * in otherwise correctly working environment the
   * probable cause is running out of file descriptors
   * (EMFILE, ENFILE or others?). The man pages for
   * accept don't seem to list these as possible,
   * although it's obvious that it may happen here.
   * Thus no specific errors are tested at this
   * point, just assume that connections cannot
   * be accepted until some old is closed first.
   */
  if (-1 == (fd = accept(listener->fd, (struct sockaddr*) &addr, &addrlen))) {
    if (EAGAIN == errno)
       return;
    /*
     * slow down the whining to opers bit
     */
    if((last_oper_notice + 20) <= CurrentTime) {
      report_error("Error accepting connection %s:%s", 
                 listener->name, errno);
      last_oper_notice = CurrentTime;
    }
    return;
  }
  /*
   * check for connection limit
   */
  if ((MAXCONNECTIONS - 10) < fd) {
    ++ServerStats->is_ref;
    /* 
     * slow down the whining to opers bit 
     */
    if((last_oper_notice + 20) <= CurrentTime) {
      sendto_realops("All connections in use. (%s)", 
                     get_listener_name(listener));
      last_oper_notice = CurrentTime;
    }
    send(fd, "ERROR :All connections in use\r\n", 32, 0);
    CLOSE(fd);
    return;
  }
  /*
   * check to see if listener is shutting down
   */
  if (!listener->active) {
    ++ServerStats->is_ref;
    send(fd, "ERROR :Use another port\r\n", 25, 0);
    CLOSE(fd);
    return;
  }
  /*
   * check conf for ip address access
   */
  if (!conf_connect_allowed(addr.SIN_ADDR)) {
    ServerStats->is_ref++;
#ifdef REPORT_DLINE_TO_USER
     send(fd, "NOTICE DLINE :*** You have been D-lined\r\n", 41, 0);
#endif
    CLOSE(fd);
    return;
  }
  ServerStats->is_ac++;
  nextping = CurrentTime;
  add_connection(listener, fd);
}