Пример #1
0
/** Start sending upings to a server.
 * @param[in] sptr Client requesting the upings.
 * @param[in] aconf ConfItem containing the address to ping.
 * @param[in] port Port number to ping.
 * @param[in] count Number of times to ping (should be at least 20).
 * @return Zero.
 */
int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count)
{
  int fd;
  struct UPing* pptr;

  assert(0 != sptr);
  assert(0 != aconf);

  if (INADDR_NONE == aconf->ipnum.s_addr) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host lookup failed for "
		  "%s", sptr, aconf->name);
    return 0;
  }

  if (IsUPing(sptr))
    uping_cancel(sptr, sptr);  /* Cancel previous ping request */

  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Unable to create udp "
		  "ping socket", sptr);
    return 0;
  }

  if (!os_set_nonblocking(fd)) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Can't set fd non-"
		  "blocking", sptr);
    close(fd);
    return 0;
  }
  pptr = (struct UPing*) MyMalloc(sizeof(struct UPing));
  assert(0 != pptr);
  memset(pptr, 0, sizeof(struct UPing));

  if (!socket_add(&pptr->socket, uping_read_callback, (void*) pptr,
		  SS_DATAGRAM, SOCK_EVENT_READABLE, fd)) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Can't queue fd for "
		  "reading", sptr);
    close(fd);
    MyFree(pptr);
    return 0;
  }

  pptr->fd                  = fd;
  pptr->sin.sin_port        = htons(port);
  pptr->sin.sin_addr.s_addr = aconf->ipnum.s_addr;
  pptr->sin.sin_family      = AF_INET;
  pptr->count               = IRCD_MIN(20, count);
  pptr->client              = sptr;
  pptr->index               = -1;
  pptr->freeable            = UPING_PENDING_SOCKET;
  strcpy(pptr->name, aconf->name);

  pptr->next = pingList;
  pingList   = pptr;

  SetUPing(sptr);
  uping_start(pptr);
  return 0;
}
Пример #2
0
/*
 * @returns 0 on success, -1 on error.
 */
int uping_init(void)
{
  struct sockaddr_in from = { 0 };
  int fd;

  memset(&from, 0, sizeof(from));
  from.sin_addr = VirtualHost.sin_addr;
  from.sin_port = htons(atoi(UDP_PORT));
  from.sin_family = AF_INET;

  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
    Debug((DEBUG_ERROR, "UPING: UDP listener socket call failed: %s", 
           (strerror(errno)) ? strerror(errno) : "Unknown error"));
    return -1;
  }
  if (!os_set_reuseaddr(fd)) {
    log_write(LS_SOCKET, L_ERROR, 0,
	      "UPING: set reuseaddr on UDP listener failed: %m (fd %d)", fd);
    Debug((DEBUG_ERROR, "UPING: set reuseaddr on UDP listener failed: %s",
           (strerror(errno)) ? strerror(errno) : "Unknown error"));
    close(fd);
    return -1;
  }
  if (bind(fd, (struct sockaddr*) &from, sizeof(from)) == -1) {
    log_write(LS_SOCKET, L_ERROR, 0,
	      "UPING: bind on UDP listener (%d fd %d) failed: %m",
	      htons(from.sin_port), fd);
    Debug((DEBUG_ERROR, "UPING: bind on UDP listener failed : %s",
           (strerror(errno)) ? strerror(errno) : "Unknown error"));
    close(fd);
    return -1;
  }
  if (!os_set_nonblocking(fd)) {
    Debug((DEBUG_ERROR, "UPING: set non-blocking: %s",
           (strerror(errno)) ? strerror(errno) : "Unknown error"));
    close(fd);
    return -1;
  }
  if (!socket_add(&upingSock, uping_echo_callback, 0, SS_DATAGRAM,
		  SOCK_EVENT_READABLE, fd)) {
    Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
    close(fd);
    return -1;
  }
  UPingFileDescriptor = fd;
  return fd;
}
/** Open a TCP or UDP socket on a particular address.
 * @param[in] local Local address to bind to.
 * @param[in] type SOCK_STREAM or SOCK_DGRAM.
 * @param[in] port_name Port name (used in error diagnostics).
 * @param[in] family A specific address family to use, or 0 for automatic.
 * @return Bound descriptor, or -1 on error.
 */
int os_socket(const struct irc_sockaddr* local, int type, const char* port_name, int family)
{
  struct sockaddr_native addr;
  int size, fd;

  assert(local != 0);
  size = sockaddr_from_irc(&addr, local, -1, family);
  fd = socket(addr.sn_family, type, 0);
  if (fd < 0) {
    report_error(SOCKET_ERROR_MSG, port_name, errno);
    return -1;
  }
  if (fd > MAXCLIENTS - 1) {
    report_error(CONNLIMIT_ERROR_MSG, port_name, 0);
    close(fd);
    return -1;
  }
  if (!os_set_reuseaddr(fd)) {
    report_error(REUSEADDR_ERROR_MSG, port_name, errno);
    close(fd);
    return -1;
  }
  if (!os_set_nonblocking(fd)) {
    report_error(NONB_ERROR_MSG, port_name, errno);
    close(fd);
    return -1;
  }
  if (local) {
#if defined(IPV6_V6ONLY)
    int on = 1;
    if (family == AF_INET6 && irc_in_addr_unspec(&local->addr))
      setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
#endif
    if (bind(fd, (struct sockaddr*)&addr, size)) {
      report_error(BIND_ERROR_MSG, port_name, errno);
      close(fd);
      return -1;
    }
  }
  return fd;
}
Пример #4
0
/*
 * start_auth_query - Flag the client to show that an attempt to 
 * contact the ident server on the client's host.  The connect and
 * subsequently the socket are all put into 'non-blocking' mode.  
 * Should the connect or any later phase of the identifing process fail,
 * it is aborted and the user is given a username of "unknown".
 */
static int start_auth_query(struct AuthRequest* auth)
{
  struct sockaddr_in remote_addr;
  struct sockaddr_in local_addr;
  int                fd;
  IOResult           result;

  assert(0 != auth);
  assert(0 != auth->client);

  if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    ++ServerStats->is_abad;
    return 0;
  }
  if ((MAXCONNECTIONS - 10) < fd) {
    close(fd);
    return 0;
  }
  if (!os_set_nonblocking(fd)) {
    close(fd);
    return 0;
  }
  if (IsUserPort(auth->client))
    sendheader(auth->client, REPORT_DO_ID);
  /* 
   * get the local address of the client and bind to that to
   * make the auth request.  This used to be done only for
   * ifdef VIRTTUAL_HOST, but needs to be done for all clients
   * since the ident request must originate from that same address--
   * and machines with multiple IP addresses are common now
   */
  memset(&local_addr, 0, sizeof(struct sockaddr_in));
  os_get_sockname(cli_fd(auth->client), &local_addr);
  local_addr.sin_port = htons(0);

  if (bind(fd, (struct sockaddr*) &local_addr, sizeof(struct sockaddr_in))) {
    close(fd);
    return 0;
  }

  remote_addr.sin_addr.s_addr = (cli_ip(auth->client)).s_addr;
  remote_addr.sin_port = htons(113);
  remote_addr.sin_family = AF_INET;

  if ((result = os_connect_nonb(fd, &remote_addr)) == IO_FAILURE ||
      !socket_add(&auth->socket, auth_sock_callback, (void*) auth,
		  result == IO_SUCCESS ? SS_CONNECTED : SS_CONNECTING,
		  SOCK_EVENT_READABLE, fd)) {
    ServerStats->is_abad++;
    /*
     * No error report from this...
     */
    close(fd);
    if (IsUserPort(auth->client))
      sendheader(auth->client, REPORT_FAIL_ID);
    return 0;
  }

  auth->flags |= AM_SOCKET;
  auth->fd = fd;

  SetAuthConnect(auth);
  if (result == IO_SUCCESS)
    send_auth_query(auth); /* this does a SetAuthPending(auth) for us */

  return 1;
}
Пример #5
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);
}
Пример #6
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);
}