Exemple #1
0
/* Depending on verbosity, print a message that a connection was established. */
static void connect_report(nsock_iod nsi)
{
    union sockaddr_u peer;
    zmem(&peer, sizeof(peer.storage));

    nsi_getlastcommunicationinfo(nsi, NULL, NULL, NULL,
        &peer.sockaddr, sizeof(peer.storage));

    if (o.verbose) {
#ifdef HAVE_OPENSSL
        if (nsi_checkssl(nsi)) {
            X509 *cert;
            X509_NAME *subject;
            char digest_buf[SHA1_STRING_LENGTH + 1];
            char *fp;

            loguser("SSL connection to %s:%hu.", inet_socktop(&peer), nsi_peerport(nsi));

            cert = SSL_get_peer_certificate((SSL *) nsi_getssl(nsi));
            ncat_assert(cert != NULL);

            subject = X509_get_subject_name(cert);
            if (subject != NULL) {
                char buf[256];
                int n;

                n = X509_NAME_get_text_by_NID(subject, NID_organizationName, buf, sizeof(buf));
                if (n >= 0 && n <= sizeof(buf) - 1)
                    loguser_noprefix(" %s", buf);
            }

            loguser_noprefix("\n");

            fp = ssl_cert_fp_str_sha1(cert, digest_buf, sizeof(digest_buf));
            ncat_assert(fp == digest_buf);
            loguser("SHA-1 fingerprint: %s\n", digest_buf);
        } else {
#if HAVE_SYS_UN_H
            if (peer.sockaddr.sa_family == AF_UNIX)
                loguser("Connected to %s.\n", peer.un.sun_path);
            else
#endif
                loguser("Connected to %s:%hu.\n", inet_socktop(&peer), nsi_peerport(nsi));
        }
#else
#if HAVE_SYS_UN_H
        if (peer.sockaddr.sa_family == AF_UNIX)
            loguser("Connected to %s.\n", peer.un.sun_path);
        else
#endif
            loguser("Connected to %s:%hu.\n", inet_socktop(&peer), nsi_peerport(nsi));
#endif
    }
}
Exemple #2
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;
}
Exemple #3
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;
}
/* 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;
}
Exemple #5
0
/* handle_connect_results assumes that select or poll have already shown the
 * descriptor to be active */
void handle_connect_result(mspool *ms, msevent *nse, enum nse_status status) {
  int optval;
  socklen_t optlen = sizeof(int);
  msiod *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:
        fprintf(stderr, "Strange connect error from %s (%d): %s",
                 inet_ntop_ez(&iod->peer, iod->peerlen), optval, socket_strerror(optval));
        assert(0); /* I'd like for someone to report it */
        break;
    }

    /* 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 (iod->hostname != NULL) {
#if HAVE_SSL_SET_TLSEXT_HOST_NAME
        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 {
    assert(0); /* Currently we only know about TIMEOUT and SUCCESS callbacks */
  }

  /* At this point the TCP connection is done, whether successful or not.
   * Therefore decrease the read/write listen counts that were incremented in
   * nsp_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)
        fprintf(stderr, "Uh-oh: SSL_set_session() failed - please tell Fyodor\n");
      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 {
        if (ms->tracelevel > 0)
          nsock_trace(ms, "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 nsp_ssl_init_max_speed. Try reconnecting with
         * SSL_OP_NO_SSLv2. Never downgrade a NO_SSLv2 connection to one that
         * might use SSLv2. */
        if (ms->tracelevel > 0)
          nsock_trace(ms, "EID %li reconnecting with SSL_OP_NO_SSLv2", nse->id);

        saved_ev = iod->watched_events;
        ms->engine->iod_unregister(ms, iod);
        close(iod->sd);
        nsock_connect_internal(ms, nse, SOCK_STREAM, iod->lastproto, &iod->peer, iod->peerlen, nsi_peerport(iod));
        ms->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 {
        if (ms->tracelevel > 0)
          nsock_trace(ms, "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
  return;
}
Exemple #6
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;
  }
}
/* 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;
}