Esempio n. 1
0
/* Same as above, except it tries to read at least 'nbytes' instead of 'nlines'. */
nsock_event_id nsock_readbytes(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
                               void *userdata, int nbytes) {

  msiod *nsi = (msiod *)ms_iod;
  mspool *ms = (mspool *)nsp;
  msevent *nse;

  nse = msevent_new(ms, NSE_TYPE_READ, nsi, timeout_msecs, handler, userdata);
  assert(nse);

  if (ms->tracelevel > 0) {
    if (nsi->peerlen > 0)
      nsock_trace(ms, "Read request for %d bytes from IOD #%li [%s:%d] EID %li",
                  nbytes, nsi->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), nse->id);
    else
      nsock_trace(ms, "Read request for %d bytes from IOD #%li (peer unspecified) EID %li",
                  nbytes, nsi->id, nse->id);
  }

  nse->readinfo.read_type = NSOCK_READBYTES;
  nse->readinfo.num = nbytes;

  nsp_add_event(ms, nse);

  return nse->id;
}
Esempio n. 2
0
static int handle_state_initial(struct npool *nsp, struct nevent *nse, void *udata) {
  struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
  struct sockaddr_storage *ss;
  size_t sslen;
  unsigned short port;
  struct proxy_node *next;
  int timeout;

  px_ctx->px_state = PROXY_STATE_HTTP_TCP_CONNECTED;

  next = proxy_ctx_node_next(px_ctx);
  if (next) {
    ss    = &next->ss;
    sslen = next->sslen;
    port  = next->port;
  } else {
    ss    = &px_ctx->target_ss;
    sslen = px_ctx->target_sslen;
    port  = px_ctx->target_port;
  }

  timeout = TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod);

  nsock_printf(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch,
               timeout, udata, "CONNECT %s:%d HTTP/1.1\r\n\r\n",
               inet_ntop_ez(ss, sslen), (int)port);

  nsock_readlines(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch,
                  timeout, udata, 1);

  return 0;
}
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod,
              nsock_ev_handler handler, int timeout_msecs,
              void *userdata, struct sockaddr *saddr, size_t sslen,
              unsigned short port, const char *data, int datalen) {
  mspool *nsp = (mspool *) ms_pool;
  msiod *nsi = (msiod *) ms_iod;
  msevent *nse;
  char displaystr[256];
  struct sockaddr_in *sin = (struct sockaddr_in *) saddr;
#if HAVE_IPV6
  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) saddr;
#endif

  nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler,
		    userdata);
  assert(nse);

  if (sin->sin_family == AF_INET) {
    sin->sin_port = htons(port);
  } else {
      assert(sin->sin_family == AF_INET6);
#if HAVE_IPV6
    sin6->sin6_port = htons(port);
#else
    fatal("IPv6 address passed to nsock_connect_* call, but nsock was not compiled w/IPv6 support");
#endif
  }

  assert(sslen <= sizeof(nse->writeinfo.dest));
  memcpy(&nse->writeinfo.dest, saddr, sslen);
  nse->writeinfo.destlen = sslen;

  assert(sslen <= sizeof(nse->iod->peer));
  memcpy(&nse->iod->peer, saddr, sslen);
  nse->iod->peerlen = sslen;

  if (datalen < 0)
    datalen = (int) strlen(data);	

  if (nsp->tracelevel > 0) {
    if (nsp->tracelevel > 1 && datalen < 80) {
      memcpy(displaystr, ": ", 2);
      memcpy(displaystr + 2, data, datalen);
      displaystr[2 + datalen] = '\0';
      replacenonprintable(displaystr + 2, datalen, '.');
    } else {
      displaystr[0] = '\0';
    }
    nsock_trace(nsp, "Sendto request for %d bytes to IOD #%li EID %li [%s:%hu]%s",
      datalen, nsi->id, nse->id,
      inet_ntop_ez(&nse->writeinfo.dest, nse->writeinfo.destlen), port,
      displaystr);
  }
	
  fscat(&nse->iobuf, data, datalen);

  nsp_add_event(nsp, nse);

  return nse->id;
}
/* Request an SSL over TCP/SCTP connection to another system (by IP address).
 * The in_addr is normal network byte order, but the port number should be given
 * in HOST BYTE ORDER.  This function will call back only after it has made the
 * connection AND done the initial SSL negotiation.  From that point on, you use
 * the normal read/write calls and decryption will happen transparently. ss
 * should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate
 * (just like what you would pass to connect).  sslen should be the sizeof the
 * structure you are passing in. */
nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, int timeout_msecs,
                                 void *userdata, struct sockaddr *saddr, size_t sslen, int proto, unsigned short port, nsock_ssl_session ssl_session) {

#ifndef HAVE_OPENSSL
  fatal("nsock_connect_ssl called - but nsock was built w/o SSL support.  QUITTING");
  return (nsock_event_id)0; /* UNREACHED */
#else
  struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;
  msiod *nsi = (msiod *)nsiod;
  mspool *ms = (mspool *)nsp;
  msevent *nse;

  if (!ms->sslctx)
    nsp_ssl_init(ms);

  assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);

  nse = msevent_new(ms, NSE_TYPE_CONNECT_SSL, nsi, timeout_msecs, handler, userdata);
  assert(nse);

  /* Set our SSL_SESSION so we can benefit from session-id reuse. */
  nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session);

  nsock_log_info(ms, "SSL connection requested to %s:%hu/%s (IOD #%li) EID %li",
                 inet_ntop_ez(ss, sslen), port, (proto == IPPROTO_TCP ? "tcp" : "sctp"),
                 nsi->id, nse->id);

  /* Do the actual connect() */
  nsock_connect_internal(ms, nse, SOCK_STREAM, proto, ss, sslen, port);
  nsp_add_event(ms, nse);

  return nse->id;
#endif /* HAVE_OPENSSL */
}
static char *get_addr_string(const struct sockaddr_storage *ss, size_t sslen) {
  static char buffer[PEER_STR_LEN];

#if HAVE_SYS_UN_H
  if (ss->ss_family == AF_UNIX) {
    sprintf(buffer, "%s", get_unixsock_path(ss));
    return buffer;
  }
#endif

  sprintf(buffer, "%s:%d", inet_ntop_ez(ss, sslen), get_port(ss));
  return buffer;
}
Esempio n. 6
0
/* Get the peer/host address string.
 * In case we have support for UNIX domain sockets, function returns
 * string containing path to UNIX socket if the address family is AF_UNIX,
 * otherwise it returns string containing "<address>:<port>". */
char *get_peeraddr_string(const msiod *iod)
{
  static char buffer[PEER_STR_LEN];

#if HAVE_SYS_UN_H
  if (iod->peer.ss_family == AF_UNIX) {
    sprintf(buffer, "%s", get_unixsock_path(&iod->peer));
    return buffer;
  }
#endif

  sprintf(buffer, "%s:%d", inet_ntop_ez(&iod->peer, iod->peerlen), nsi_peerport((msiod *) iod));
  return buffer;
}
Esempio n. 7
0
/* Request a UDP "connection" to another system (by IP address).  The in_addr is
 * normal network byte order, but the port number should be given in HOST BYTE
 * ORDER.  Since this is UDP, no packets are actually sent.  The destination IP
 * and port are just associated with the nsiod (an actual OS connect() call is
 * made).  You can then use the normal nsock write calls on the socket.  There
 * is no timeout since this call always calls your callback at the next
 * opportunity.  The advantages to having a connected UDP socket (as opposed to
 * just specifying an address with sendto() are that we can now use a consistent
 * set of write/read calls for TCP/UDP, received packets from the non-partner
 * are automatically dropped by the OS, and the OS can provide asynchronous
 * errors (see Unix Network Programming pp224).  ss should be a
 * sockaddr_storage, sockaddr_in6, or sockaddr_in as appropriate (just like what
 * you would pass to connect).  sslen should be the sizeof the structure you are
 * passing in. */
nsock_event_id nsock_connect_udp(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handler handler, void *userdata,
                                 struct sockaddr *saddr, size_t sslen, unsigned short port) {

  struct niod *nsi = (struct niod *)nsiod;
  struct npool *ms = (struct npool *)nsp;
  struct nevent *nse;
  struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;

  assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);

  nse = event_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata);
  assert(nse);

  nsock_log_info("UDP connection requested to %s:%hu (IOD #%li) EID %li",
                 inet_ntop_ez(ss, sslen), port, nsi->id, nse->id);

  nsock_connect_internal(ms, nse, SOCK_DGRAM, IPPROTO_UDP, ss, sslen, port);
  nsock_pool_add_event(ms, nse);

  return nse->id;
}
/* Request a TCP connection to another system (by IP address).  The in_addr is
 * normal network byte order, but the port number should be given in HOST BYTE
 * ORDER.  ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as
 * appropriate (just like what you would pass to connect).  sslen should be the
 * sizeof the structure you are passing in. */
nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
                                 void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port) {
  msiod *nsi = (msiod *)ms_iod;
  mspool *ms = (mspool *)nsp;
  msevent *nse;
  struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr;

  assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);

  nse = msevent_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata);
  assert(nse);

  nsock_log_info(ms, "TCP connection requested to %s:%hu (IOD #%li) EID %li",
                 inet_ntop_ez(ss, sslen), port, nsi->id, nse->id);

  /* Do the actual connect() */
  nsock_connect_internal(ms, nse, SOCK_STREAM, IPPROTO_TCP, ss, sslen, port);
  nsp_add_event(ms, nse);

  return nse->id;
}
/* Write some data to the socket.  If the write is not COMPLETED within timeout_msecs , NSE_STATUS_TIMEOUT will be returned.  If you are supplying NUL-terminated data, you can optionally pass -1 for datalen and nsock_write will figure out the length itself */
nsock_event_id  nsock_write(nsock_pool ms_pool, nsock_iod ms_iod, 
		      nsock_ev_handler handler, int timeout_msecs, 
		      void *userdata, const char *data, int datalen) {
  mspool *nsp = (mspool *) ms_pool;
  msiod *nsi = (msiod *) ms_iod;
  msevent *nse;
  char displaystr[256];

  nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler,
		    userdata);
  assert(nse);

  nse->writeinfo.dest.ss_family = AF_UNSPEC;

  if (datalen < 0)
    datalen = (int) strlen(data);

  if (nsp->tracelevel > 0) {
    if (nsp->tracelevel > 1 && datalen < 80) {
      memcpy(displaystr, ": ", 2);
      memcpy(displaystr + 2, data, datalen);
      displaystr[2 + datalen] = '\0';
      replacenonprintable(displaystr + 2, datalen, '.');
    } else displaystr[0] = '\0';
    if (nsi->peerlen > 0)
      nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li [%s:%hu]%s", datalen, nsi->id, 
		  nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), displaystr);
    else 
      nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", datalen, 
		  nsi->id, nse->id, displaystr);
  }

  fscat(&nse->iobuf, data, datalen);

  nsp_add_event(nsp, nse);
  
  return nse->id;
}
Esempio n. 10
0
/* handle_connect_results assumes that select or poll have already shown the
 * descriptor to be active */
void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
  int optval;
  socklen_t optlen = sizeof(int);
  struct niod *iod = nse->iod;
#if HAVE_OPENSSL
  int sslerr;
  int rc = 0;
  int sslconnect_inprogress = nse->type == NSE_TYPE_CONNECT_SSL && nse->iod &&
    (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ ||
     nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE);
#else
  int sslconnect_inprogress = 0;
#endif

  if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) {
    nse->status = status;
    nse->event_done = 1;
  } else if (sslconnect_inprogress) {
    /* Do nothing */
  } else if (status == NSE_STATUS_SUCCESS) {
    /* First we want to determine whether the socket really is connected */
    if (getsockopt(iod->sd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen) != 0)
      optval = socket_errno(); /* Stupid Solaris */

    switch (optval) {
      case 0:
        nse->status = NSE_STATUS_SUCCESS;
        break;
      /* EACCES can be caused by ICMPv6 dest-unreach-admin, or when a port is
         blocked by Windows Firewall (WSAEACCES). */
      case EACCES:
      case ECONNREFUSED:
      case EHOSTUNREACH:
      case ENETDOWN:
      case ENETUNREACH:
      case ENETRESET:
      case ECONNABORTED:
      case ETIMEDOUT:
      case EHOSTDOWN:
      case ECONNRESET:
#ifdef WIN32
      case WSAEADDRINUSE:
      case WSAEADDRNOTAVAIL:
#endif
#ifndef WIN32
      case EPIPE: /* Has been seen after connect on Linux. */
      case ENOPROTOOPT: /* Also seen on Linux, perhaps in response to protocol unreachable. */
#endif
        nse->status = NSE_STATUS_ERROR;
        nse->errnum = optval;
        break;

      default:
        /* I'd like for someone to report it */
        fatal("Strange connect error from %s (%d): %s",
              inet_ntop_ez(&iod->peer, iod->peerlen), optval,
              socket_strerror(optval));
    }

    /* Now special code for the SSL case where the TCP connection was successful. */
    if (nse->type == NSE_TYPE_CONNECT_SSL &&
        nse->status == NSE_STATUS_SUCCESS) {
#if HAVE_OPENSSL
      assert(ms->sslctx != NULL);
      /* Reuse iod->ssl if present. If set, this is the second try at connection
         without the SSL_OP_NO_SSLv2 option set. */
      if (iod->ssl == NULL) {
        iod->ssl = SSL_new(ms->sslctx);
        if (!iod->ssl)
          fatal("SSL_new failed: %s", ERR_error_string(ERR_get_error(), NULL));
      }

#if HAVE_SSL_SET_TLSEXT_HOST_NAME
      if (iod->hostname != NULL) {
        if (SSL_set_tlsext_host_name(iod->ssl, iod->hostname) != 1)
          fatal("SSL_set_tlsext_host_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
      }
#endif

      /* Associate our new SSL with the connected socket.  It will inherit the
       * non-blocking nature of the sd */
      if (SSL_set_fd(iod->ssl, iod->sd) != 1)
        fatal("SSL_set_fd failed: %s", ERR_error_string(ERR_get_error(), NULL));

      /* Event not done -- need to do SSL connect below */
      nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT;
#endif
    } else {
      /* This is not an SSL connect (in which case we are always done), or the
       * TCP connect() underlying the SSL failed (in which case we are also done */
      nse->event_done = 1;
    }
  } else {
    fatal("Unknown status (%d)", status);
  }

  /* At this point the TCP connection is done, whether successful or not.
   * Therefore decrease the read/write listen counts that were incremented in
   * nsock_pool_add_event. In the SSL case, we may increase one of the counts depending
   * on whether SSL_connect returns an error of SSL_ERROR_WANT_READ or
   * SSL_ERROR_WANT_WRITE. In that case we will re-enter this function, but we
   * don't want to execute this block again. */
  if (iod->sd != -1 && !sslconnect_inprogress) {
    int ev = EV_NONE;

    ev |= socket_count_read_dec(iod);
    ev |= socket_count_write_dec(iod);
    ev |= EV_EXCEPT;
    update_events(iod, ms, EV_NONE, ev);
  }

#if HAVE_OPENSSL
  if (nse->type == NSE_TYPE_CONNECT_SSL && !nse->event_done) {
    /* Lets now start/continue/finish the connect! */
    if (iod->ssl_session) {
      rc = SSL_set_session(iod->ssl, iod->ssl_session);
      if (rc == 0)
        nsock_log_error("Uh-oh: SSL_set_session() failed - please tell [email protected]");
      iod->ssl_session = NULL; /* No need for this any more */
    }

    /* If this is a reinvocation of handle_connect_result, clear out the listen
     * bits that caused it, based on the previous SSL desire. */
    if (sslconnect_inprogress) {
      int ev;

      ev = socket_count_dec_ssl_desire(nse);
      update_events(iod, ms, EV_NONE, ev);
    }

    rc = SSL_connect(iod->ssl);
    if (rc == 1) {
      /* Woop!  Connect is done! */
      nse->event_done = 1;
      /* Check that certificate verification was okay, if requested. */
      if (nsi_ssl_post_connect_verify(iod)) {
        nse->status = NSE_STATUS_SUCCESS;
      } else {
        nsock_log_error("certificate verification error for EID %li: %s",
                        nse->id, ERR_error_string(ERR_get_error(), NULL));
        nse->status = NSE_STATUS_ERROR;
      }
    } else {
      long options = SSL_get_options(iod->ssl);

      sslerr = SSL_get_error(iod->ssl, rc);
      if (rc == -1 && sslerr == SSL_ERROR_WANT_READ) {
        nse->sslinfo.ssl_desire = sslerr;
        socket_count_read_inc(iod);
        update_events(iod, ms, EV_READ, EV_NONE);
      } else if (rc == -1 && sslerr == SSL_ERROR_WANT_WRITE) {
        nse->sslinfo.ssl_desire = sslerr;
        socket_count_write_inc(iod);
        update_events(iod, ms, EV_WRITE, EV_NONE);
      } else if (!(options & SSL_OP_NO_SSLv2)) {
        int saved_ev;

        /* SSLv3-only and TLSv1-only servers can't be connected to when the
         * SSL_OP_NO_SSLv2 option is not set, which is the case when the pool
         * was initialized with nsock_pool_ssl_init_max_speed. Try reconnecting
         * with SSL_OP_NO_SSLv2. Never downgrade a NO_SSLv2 connection to one
         * that might use SSLv2. */
        nsock_log_info("EID %li reconnecting with SSL_OP_NO_SSLv2", nse->id);

        saved_ev = iod->watched_events;
        nsock_engine_iod_unregister(ms, iod);
        close(iod->sd);
        nsock_connect_internal(ms, nse, SOCK_STREAM, iod->lastproto, &iod->peer,
                               iod->peerlen, nsock_iod_get_peerport(iod));
        nsock_engine_iod_register(ms, iod, saved_ev);

        SSL_clear(iod->ssl);
        if(!SSL_clear(iod->ssl))
           fatal("SSL_clear failed: %s", ERR_error_string(ERR_get_error(), NULL));

        SSL_set_options(iod->ssl, options | SSL_OP_NO_SSLv2);
        socket_count_read_inc(nse->iod);
        socket_count_write_inc(nse->iod);
        update_events(iod, ms, EV_READ|EV_WRITE, EV_NONE);
        nse->sslinfo.ssl_desire = SSL_ERROR_WANT_CONNECT;
      } else {
        nsock_log_info("EID %li %s",
                       nse->id, ERR_error_string(ERR_get_error(), NULL));
        nse->event_done = 1;
        nse->status = NSE_STATUS_ERROR;
        nse->errnum = EIO;
      }
    }
  }
#endif
}
Esempio n. 11
0
/* An event has been completed and the handler is about to be called. This
 * function writes out tracing data about the event if necessary */
void nsock_trace_handler_callback(mspool *ms, msevent *nse) {
  msiod *nsi;
  char *str;
  int strlength = 0;
  char displaystr[256];
  char errstr[256];

  if (ms->tracelevel == 0)
    return;

  nsi = nse->iod;

  if (nse->status == NSE_STATUS_ERROR)
    Snprintf(errstr, sizeof(errstr), "[%s (%d)] ", strerror(nse->errnum), nse->errnum);
  else
    errstr[0] = '\0';

  /* Some types have special tracing treatment */
  switch(nse->type) {
    case NSE_TYPE_CONNECT:
    case NSE_TYPE_CONNECT_SSL:
      nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s:%d]",
                  nse_type2str(nse->type), nse_status2str(nse->status), errstr,
                  nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi));
      break;

    case NSE_TYPE_READ:
      if (nse->status != NSE_STATUS_SUCCESS) {
        if (nsi->peerlen > 0) {
           nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s:%d]",
                       nse_type2str(nse->type), nse_status2str(nse->status),
                       errstr, nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen),
                       nsi_peerport(nsi));
        } else {
          nsock_trace(ms, "Callback: %s %s %sfor EID %li (peer unspecified)",
                      nse_type2str(nse->type), nse_status2str(nse->status),
                      errstr, nse->id);
        }
      } else {
        str = nse_readbuf(nse, &strlength);
        if (ms->tracelevel > 1 && strlength < 80) {
          memcpy(displaystr, ": ", 2);
          memcpy(displaystr + 2, str, strlength);
          displaystr[2 + strlength] = '\0';
          replacenonprintable(displaystr + 2, strlength, '.');
        } else {
          displaystr[0] = '\0';
        }

        if (nsi->peerlen > 0) {
          nsock_trace(ms, "Callback: %s %s for EID %li [%s:%d] %s(%d bytes)%s",
                      nse_type2str(nse->type), nse_status2str(nse->status),
                      nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen),
                      nsi_peerport(nsi), nse_eof(nse)? "[EOF]" : "", strlength,
                      displaystr);
        } else {
          nsock_trace(ms, "Callback %s %s for EID %li (peer unspecified) %s(%d bytes)%s",
                      nse_type2str(nse->type), nse_status2str(nse->status),
                      nse->id, nse_eof(nse)? "[EOF]" : "", strlength, displaystr);
        }
      }
      break;

    case NSE_TYPE_WRITE:
      nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s:%d]",
                  nse_type2str(nse->type), nse_status2str(nse->status), errstr,
                  nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen),
                  nsi_peerport(nsi));
      break;

    case NSE_TYPE_TIMER:
      nsock_trace(ms, "Callback: %s %s %sfor EID %li",
                  nse_type2str(nse->type), nse_status2str(nse->status), errstr,
                  nse->id);
      break;

#if HAVE_PCAP
    case NSE_TYPE_PCAP_READ:
      nsock_trace(ms, "Callback: %s %s %sfor EID %li ",
                  nse_type2str(nse->type), nse_status2str(nse->status),
                  errstr, nse->id);
      break;
#endif

    default:
      assert(0);
      break;
  }
}
Esempio n. 12
0
/* This is sufficiently different from the TCP code (wrt SSL, etc) that it
 * resides in its own simpler function
 */
static int ncat_listen_dgram(int proto)
{
    struct {
        int fd;
        union sockaddr_u addr;
    } sockfd[NUM_LISTEN_ADDRS];
    int i, fdn = -1;
    int fdmax, nbytes, n, fds_ready;
    char buf[DEFAULT_UDP_BUF_LEN] = { 0 };
    char *tempbuf = NULL;
    fd_set read_fds;
    union sockaddr_u remotess;
    socklen_t sslen = sizeof(remotess.storage);
    struct timeval tv;
    struct timeval *tvp = NULL;
    unsigned int num_sockets;

    for (i = 0; i < NUM_LISTEN_ADDRS; i++) {
        sockfd[i].fd = -1;
        sockfd[i].addr.storage.ss_family = AF_UNSPEC;
    }

    FD_ZERO(&read_fds);

    /* Initialize remotess struct so recvfrom() doesn't hit the fan.. */
    zmem(&remotess.storage, sizeof(remotess.storage));
    remotess.storage.ss_family = o.af;

#ifdef WIN32
    set_pseudo_sigchld_handler(decrease_conn_count);
#else
    /* Reap on SIGCHLD */
    Signal(SIGCHLD, sigchld_handler);
    /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
       send data to it before noticing. */
    Signal(SIGPIPE, SIG_IGN);
#endif

/* Not sure if this problem exists on Windows, but fcntl and /dev/null don't */
#ifndef WIN32
    /* Check whether stdin is closed. Because we treat this fd specially, we
     * can't risk it being reopened for an incoming connection, so we'll hold
     * it open instead. */
    if (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF) {
      logdebug("stdin is closed, attempting to reserve STDIN_FILENO\n");
      i = open("/dev/null", O_RDONLY);
      if (i >= 0 && i != STDIN_FILENO) {
        /* Oh well, we tried */
        logdebug("Couldn't reserve STDIN_FILENO\n");
        close(i);
      }
    }
#endif

    /* set for selecting udp listening sockets */
    fd_set listen_fds;
    fd_list_t listen_fdlist;
    FD_ZERO(&listen_fds);
    init_fdlist(&listen_fdlist, num_listenaddrs);

    num_sockets = 0;
    for (i = 0; i < num_listenaddrs; i++) {
        /* create the UDP listen sockets */
        sockfd[num_sockets].fd = do_listen(SOCK_DGRAM, proto, &listenaddrs[i]);
        if (sockfd[num_sockets].fd == -1) {
            if (o.debug > 0)
                logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
            continue;
        }
        FD_SET(sockfd[num_sockets].fd, &listen_fds);
        add_fd(&listen_fdlist, sockfd[num_sockets].fd);
        sockfd[num_sockets].addr = listenaddrs[i];
        num_sockets++;
    }
    if (num_sockets == 0) {
        if (num_listenaddrs == 1)
            bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno()));
        else
            bye("Unable to open any listening sockets.");
    }

    if (o.idletimeout > 0)
        tvp = &tv;

    while (1) {
        int i, j, conn_count, socket_n;

        if (fdn != -1) {
            /*remove socket descriptor which is burnt */
            FD_CLR(sockfd[fdn].fd, &listen_fds);
            rm_fd(&listen_fdlist, sockfd[fdn].fd);

            /* Rebuild the udp socket which got burnt */
            sockfd[fdn].fd = do_listen(SOCK_DGRAM, proto, &sockfd[fdn].addr);
            if (sockfd[fdn].fd == -1)
                bye("do_listen: %s", socket_strerror(socket_errno()));
            FD_SET(sockfd[fdn].fd, &listen_fds);
            add_fd(&listen_fdlist, sockfd[fdn].fd);

        }
        fdn = -1;
        socket_n = -1;
        fd_set fds;
        FD_ZERO(&fds);
        while (1) {
            /*
             * We just select to get a list of sockets which we can talk to
             */
            if (o.debug > 1)
                logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax);
            fds = listen_fds;

            if (o.idletimeout > 0)
                ms_to_timeval(tvp, o.idletimeout);

            fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, tvp);

            if (o.debug > 1)
                logdebug("select returned %d fds ready\n", fds_ready);

            if (fds_ready == 0)
                bye("Idle timeout expired (%d ms).", o.idletimeout);

            /*
             * Figure out which listening socket got a connection. This loop should
             * really call a function for each ready socket instead of breaking on
             * the first one.
             */
            for (i = 0; i <= listen_fdlist.fdmax && fds_ready > 0; i++) {
                /* Loop through descriptors until there is something ready */
                if (!FD_ISSET(i, &fds))
                    continue;

                /* Check each listening socket */
                for (j = 0; j < num_sockets; j++) {
                    if (i == sockfd[j].fd) {
                        if (o.debug > 1)
                            logdebug("Valid descriptor %d \n", i);
                        fdn = j;
                        socket_n = i;
                        break;
                    }
                }

                /* if we found a valid socket break */
                if (fdn != -1) {
                    fds_ready--;
                    break;
                }
            }

            /* Make sure someone connected */
            if (fdn == -1)
                continue;

            /*
             * We just peek so we can get the client connection details without
             * removing anything from the queue. Sigh.
             */
            nbytes = recvfrom(socket_n, buf, sizeof(buf), MSG_PEEK,
                              &remotess.sockaddr, &sslen);
            if (nbytes < 0) {
                loguser("%s.\n", socket_strerror(socket_errno()));
                close(socket_n);
                return 1;
            }

            /* Check conditions that might cause us to deny the connection. */
            conn_count = get_conn_count();
            if (conn_count >= o.conn_limit) {
                if (o.verbose)
                    loguser("New connection denied: connection limit reached (%d)\n", conn_count);
            } else if (!allow_access(&remotess)) {
                if (o.verbose)
                    loguser("New connection denied: not allowed\n");
            } else {
                /* Good to go. */
                break;
            }

            /* Dump the current datagram */
            nbytes = recv(socket_n, buf, sizeof(buf), 0);
            if (nbytes < 0) {
                loguser("%s.\n", socket_strerror(socket_errno()));
                close(socket_n);
                return 1;
            }
            ncat_log_recv(buf, nbytes);
        }

        if (o.debug > 1)
            logdebug("Valid Connection from %d\n", socket_n);

        conn_inc++;

        /*
         * We're using connected udp. This has the down side of only
         * being able to handle one udp client at a time
         */
        Connect(socket_n, &remotess.sockaddr, sslen);

        /* clean slate for buf */
        zmem(buf, sizeof(buf));

        /* are we executing a command? then do it */
        if (o.cmdexec) {
            struct fdinfo info = { 0 };

            info.fd = socket_n;
            if (o.keepopen)
                netrun(&info, o.cmdexec);
            else
                netexec(&info, o.cmdexec);
            continue;
        }

        FD_SET(socket_n, &read_fds);
        FD_SET(STDIN_FILENO, &read_fds);
        fdmax = socket_n;

        /* stdin -> socket and socket -> stdout */
        while (1) {
            fd_set fds;

            fds = read_fds;

            if (o.debug > 1)
                logdebug("udp select'ing\n");

            if (o.idletimeout > 0)
                ms_to_timeval(tvp, o.idletimeout);

            fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, tvp);

            if (fds_ready == 0)
                bye("Idle timeout expired (%d ms).", o.idletimeout);

            if (FD_ISSET(STDIN_FILENO, &fds)) {
                nbytes = Read(STDIN_FILENO, buf, sizeof(buf));
                if (nbytes <= 0) {
                    if (nbytes < 0 && o.verbose) {
                        logdebug("Error reading from stdin: %s\n", strerror(errno));
                    } else if (nbytes == 0 && o.debug) {
                        logdebug("EOF on stdin\n");
                    }
                    FD_CLR(STDIN_FILENO, &read_fds);
                    if (nbytes < 0)
                        return 1;
                    continue;
                }
                if (o.crlf)
                    fix_line_endings((char *) buf, &nbytes, &tempbuf, &crlf_state);
                if (!o.recvonly) {
                    if (tempbuf != NULL)
                        n = send(socket_n, tempbuf, nbytes, 0);
                    else
                        n = send(socket_n, buf, nbytes, 0);
                    if (n < nbytes) {
                        loguser("%s.\n", socket_strerror(socket_errno()));
                        close(socket_n);
                        return 1;
                    }
                    ncat_log_send(buf, nbytes);
                }
                if (tempbuf != NULL) {
                    free(tempbuf);
                    tempbuf = NULL;
                }
            }
            if (FD_ISSET(socket_n, &fds)) {
                nbytes = recv(socket_n, buf, sizeof(buf), 0);
                if (nbytes < 0) {
                    loguser("%s.\n", socket_strerror(socket_errno()));
                    close(socket_n);
                    return 1;
                }
                ncat_log_recv(buf, nbytes);
                if (!o.sendonly)
                    Write(STDOUT_FILENO, buf, nbytes);
            }

            zmem(buf, sizeof(buf));
        }
    }

    return 0;
}
Esempio n. 13
0
static int ncat_listen_stream(int proto)
{
    int rc, i, fds_ready;
    fd_set listen_fds;
    struct timeval tv;
    struct timeval *tvp = NULL;
    unsigned int num_sockets;

    /* clear out structs */
    FD_ZERO(&master_readfds);
    FD_ZERO(&master_writefds);
    FD_ZERO(&master_broadcastfds);
    FD_ZERO(&listen_fds);
#ifdef HAVE_OPENSSL
    FD_ZERO(&sslpending_fds);
#endif
    zmem(&client_fdlist, sizeof(client_fdlist));
    zmem(&broadcast_fdlist, sizeof(broadcast_fdlist));

#ifdef WIN32
    set_pseudo_sigchld_handler(decrease_conn_count);
#else
    /* Reap on SIGCHLD */
    Signal(SIGCHLD, sigchld_handler);
    /* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
       send data to it before noticing. */
    Signal(SIGPIPE, SIG_IGN);
#endif

#ifdef HAVE_OPENSSL
    if (o.ssl)
        setup_ssl_listen();
#endif

/* Not sure if this problem exists on Windows, but fcntl and /dev/null don't */
#ifndef WIN32
    /* Check whether stdin is closed. Because we treat this fd specially, we
     * can't risk it being reopened for an incoming connection, so we'll hold
     * it open instead. */
    if (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF) {
      logdebug("stdin is closed, attempting to reserve STDIN_FILENO\n");
      rc = open("/dev/null", O_RDONLY);
      if (rc >= 0 && rc != STDIN_FILENO) {
        /* Oh well, we tried */
        logdebug("Couldn't reserve STDIN_FILENO\n");
        close(rc);
      }
    }
#endif

    /* We need a list of fds to keep current fdmax. The second parameter is a
       number added to the supplied connection limit, that will compensate
       maxfds for the added by default listen and stdin sockets. */
    init_fdlist(&client_fdlist, sadd(o.conn_limit, num_listenaddrs + 1));

    for (i = 0; i < NUM_LISTEN_ADDRS; i++)
        listen_socket[i] = -1;

    num_sockets = 0;
    for (i = 0; i < num_listenaddrs; i++) {
        /* setup the main listening socket */
        listen_socket[num_sockets] = do_listen(SOCK_STREAM, proto, &listenaddrs[i]);
        if (listen_socket[num_sockets] == -1) {
            if (o.debug > 0)
                logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
            continue;
        }

        /* Make our listening socket non-blocking because there are timing issues
         * which could cause us to block on accept() even though select() says it's
         * readable.  See UNPv1 2nd ed, p422 for more.
         */
        unblock_socket(listen_socket[num_sockets]);

        /* setup select sets and max fd */
        FD_SET(listen_socket[num_sockets], &master_readfds);
        add_fd(&client_fdlist, listen_socket[num_sockets]);

        FD_SET(listen_socket[num_sockets], &listen_fds);

        num_sockets++;
    }
    if (num_sockets == 0) {
        if (num_listenaddrs == 1)
            bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno()));
        else
            bye("Unable to open any listening sockets.");
    }

    add_fd(&client_fdlist, STDIN_FILENO);

    init_fdlist(&broadcast_fdlist, o.conn_limit);

    if (o.idletimeout > 0)
        tvp = &tv;

    while (1) {
        /* We pass these temporary descriptor sets to fselect, since fselect
           modifies the sets it receives. */
        fd_set readfds = master_readfds, writefds = master_writefds;
        struct fdinfo *fdi = NULL;

        if (o.debug > 1)
            logdebug("selecting, fdmax %d\n", client_fdlist.fdmax);

        if (o.debug > 1 && o.broker)
            logdebug("Broker connection count is %d\n", get_conn_count());

        if (o.idletimeout > 0)
            ms_to_timeval(tvp, o.idletimeout);

        fds_ready = fselect(client_fdlist.fdmax + 1, &readfds, &writefds, NULL, tvp);

        if (o.debug > 1)
            logdebug("select returned %d fds ready\n", fds_ready);

        if (fds_ready == 0)
            bye("Idle timeout expired (%d ms).", o.idletimeout);

        /*
         * FIXME: optimize this loop to look only at the fds in the fd list,
         * doing it this way means that if you have one descriptor that is very
         * large, say 500, and none close to it, that you'll loop many times for
         * nothing.
         */
        for (i = 0; i <= client_fdlist.fdmax && fds_ready > 0; i++) {
            /* Loop through descriptors until there's something to read */
            if (!FD_ISSET(i, &readfds) && !FD_ISSET(i, &writefds))
                continue;

            if (o.debug > 1)
                logdebug("fd %d is ready\n", i);

#ifdef HAVE_OPENSSL
            /* Is this an ssl socket pending a handshake? If so handle it. */
            if (o.ssl && FD_ISSET(i, &sslpending_fds)) {
                FD_CLR(i, &master_readfds);
                FD_CLR(i, &master_writefds);
                fdi = get_fdinfo(&client_fdlist, i);
                ncat_assert(fdi != NULL);
                switch (ssl_handshake(fdi)) {
                case NCAT_SSL_HANDSHAKE_COMPLETED:
                    /* Clear from sslpending_fds once ssl is established */
                    FD_CLR(i, &sslpending_fds);
                    post_handle_connection(*fdi);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_WRITE:
                    FD_SET(i, &master_writefds);
                    break;
                case NCAT_SSL_HANDSHAKE_PENDING_READ:
                    FD_SET(i, &master_readfds);
                    break;
                case NCAT_SSL_HANDSHAKE_FAILED:
                default:
                    SSL_free(fdi->ssl);
                    Close(fdi->fd);
                    FD_CLR(i, &sslpending_fds);
                    FD_CLR(i, &master_readfds);
                    rm_fd(&client_fdlist, i);
                    /* Are we in single listening mode(without -k)? If so
                       then we should quit also. */
                    if (!o.keepopen && !o.broker)
                        return 1;
                    --conn_inc;
                    break;
                }
            } else
#endif
            if (FD_ISSET(i, &listen_fds)) {
                /* we have a new connection request */
                handle_connection(i);
            } else if (i == STDIN_FILENO) {
                if (o.broker) {
                    read_and_broadcast(i);
                } else {
                    /* Read from stdin and write to all clients. */
                    rc = read_stdin();
                    if (rc == 0) {
                        if (o.proto != IPPROTO_TCP || (o.proto == IPPROTO_TCP && o.sendonly)) {
                            /* There will be nothing more to send. If we're not
                               receiving anything, we can quit here. */
                            return 0;
                        }
                        if (!o.noshutdown) shutdown_sockets(SHUT_WR);
                    }
                    if (rc < 0)
                        return 1;
                }
            } else if (!o.sendonly) {
                if (o.broker) {
                    read_and_broadcast(i);
                } else {
                    /* Read from a client and write to stdout. */
                    rc = read_socket(i);
                    if (rc <= 0 && !o.keepopen)
                        return rc == 0 ? 0 : 1;
                }
            }

            fds_ready--;
        }
    }

    return 0;
}
Esempio n. 14
0
/* Same as nsock_write except you can use a printf-style format and you can only use this for ASCII strings */
nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod, 
		      nsock_ev_handler handler, int timeout_msecs, 
		      void *userdata, char *format, ... ) {

  mspool *nsp = (mspool *) ms_pool;
  msiod *nsi = (msiod *) ms_iod;
  msevent *nse;
  char buf[4096];
  char *buf2 = NULL;
  int res, res2;
  int strlength = 0;
  char displaystr[256];

  va_list ap; 
  va_start(ap,format);

  nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler,
		    userdata);
  assert(nse);

  res = Vsnprintf(buf, sizeof(buf), format, ap);
  va_end(ap);

  if (res != -1) {
    if (res > sizeof(buf)) {
      buf2 = (char * ) safe_malloc(res + 16);
      res2 = Vsnprintf(buf2, sizeof(buf), format, ap);
      if (res2 == -1 || res2 > res) {
	free(buf2);
	buf2 = NULL;
      } else strlength = res2;
    } else {
      buf2 = buf;
      strlength = res;
    }
  }

  if (!buf2) {
    nse->event_done = 1;
    nse->status = NSE_STATUS_ERROR;
    nse->errnum = EMSGSIZE;
  } else {
    if (strlength == 0) {
      nse->event_done = 1;
      nse->status = NSE_STATUS_SUCCESS;      
    } else {    
      fscat(&nse->iobuf, buf2, strlength);
    }
  }

  if (nsp->tracelevel > 0) {
    if (nsp->tracelevel > 1 && nse->status != NSE_STATUS_ERROR && strlength < 80) {
      memcpy(displaystr, ": ", 2);
      memcpy(displaystr + 2, buf2, strlength);
      displaystr[2 + strlength] = '\0';
      replacenonprintable(displaystr + 2, strlength, '.');
    } else displaystr[0] = '\0';
    if (nsi->peerlen > 0)
      nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li [%s:%hu]%s", strlength, nsi->id, 
		  nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), displaystr);
    else 
      nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", strlength, 
		  nsi->id, nse->id, displaystr);
  }

  if (buf2 != buf) {
    free(buf2);
  }

  nsp_add_event(nsp, nse);

  return nse->id;
}
Esempio n. 15
0
/*
 * Simple forking HTTP proxy. It is an HTTP/1.0 proxy with knowledge of
 * HTTP/1.1. (The things lacking for HTTP/1.1 are the chunked transfer encoding
 * and the expect mechanism.) The proxy supports the CONNECT, GET, HEAD, and
 * POST methods. It supports Basic and Digest authentication of clients (use the
 * --proxy-auth option).
 *
 * HTTP/1.1 is defined in RFC 2616. Many comments refer to that document.
 * http://tools.ietf.org/html/rfc2616
 *
 * HTTP authentication is discussed in RFC 2617.
 * http://tools.ietf.org/html/rfc2617
 *
 * The CONNECT method is documented in an Internet draft and is specified as the
 * way to proxy HTTPS in RFC 2817, section 5.
 * http://tools.ietf.org/html/draft-luotonen-web-proxy-tunneling-01
 * http://tools.ietf.org/html/rfc2817#section-5
 *
 * The CONNECT method is not limited to HTTP, but is potentially capable of
 * connecting to any TCP port on any host. The proxy connection is requested
 * with an HTTP request, but after that, the proxy does no interpretation of the
 * data passing through it. See section 6 of the above mentioned draft for the
 * security implications.
 */
int ncat_http_server(void)
{
    int c, i, j;
    int listen_socket[NUM_LISTEN_ADDRS];
    socklen_t sslen;
    union sockaddr_u conn;
    struct timeval tv;
    struct timeval *tvp = NULL;
    unsigned int num_sockets;

#ifndef WIN32
    Signal(SIGCHLD, proxyreaper);
#endif

#if HAVE_HTTP_DIGEST
    http_digest_init_secret();
#endif

#ifdef HAVE_OPENSSL
    if (o.ssl)
        setup_ssl_listen();
#endif
    /* Clear the socket list */
    for (i = 0; i < NUM_LISTEN_ADDRS; i++)
        listen_socket[i] = -1;

    /* set for selecting listening sockets */
    fd_set listen_fds;
    fd_list_t listen_fdlist;
    FD_ZERO(&listen_fds);
    init_fdlist(&listen_fdlist, num_listenaddrs);

    /* Listen on each address, set up lists for select */
    num_sockets = 0;
    for (i = 0; i < num_listenaddrs; i++) {
        listen_socket[num_sockets] = do_listen(SOCK_STREAM, IPPROTO_TCP, &listenaddrs[i]);
        if (listen_socket[num_sockets] == -1) {
            if (o.debug > 0)
                logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
            continue;
        }

        /* make us not block on accepts in weird cases. See ncat_listen.c:209 */
        unblock_socket(listen_socket[num_sockets]);

        /* setup select sets and max fd */
        FD_SET(listen_socket[num_sockets], &listen_fds);
        add_fd(&listen_fdlist, listen_socket[num_sockets]);

        num_sockets++;
    }
    if (num_sockets == 0) {
        if (num_listenaddrs == 1)
            bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno()));
        else
            bye("Unable to open any listening sockets.");
    }

    if (o.idletimeout > 0)
        tvp = &tv;

    for (;;) {
        fd_set read_fds;

        sslen = sizeof(conn.storage);
        /*
         * We just select to get a list of sockets which we can talk to
         */
        if (o.debug > 1)
            logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax);
        read_fds = listen_fds;

        if (o.idletimeout > 0)
            ms_to_timeval(tvp, o.idletimeout);

        int fds_ready = fselect(listen_fdlist.fdmax + 1, &read_fds, NULL, NULL, tvp);

        if (o.debug > 1)
            logdebug("select returned %d fds ready\n", fds_ready);

        if (fds_ready == 0)
            bye("Idle timeout expired (%d ms).", o.idletimeout);

        for (i = 0; i <= listen_fdlist.fdmax && fds_ready > 0; i++) {
            /* Loop through descriptors until there is something ready */
            if (!FD_ISSET(i, &read_fds))
                continue;

            /* Check each listening socket */
            for (j = 0; j < num_sockets; j++) {
                if (i == listen_socket[j]) {
                    fds_ready--;
                    c = accept(i, &conn.sockaddr, &sslen);

                    if (c == -1) {
                        if (errno == EINTR)
                            continue;
                        die("accept");
                    }

                    if (!allow_access(&conn)) {
                        Close(c);
                        continue;
                    }
                    if (o.debug > 1)
                        logdebug("forking handler for %d\n", i);
                    fork_handler(i, c);
                }
            }
        }
    }
    return 0;
}