Beispiel #1
0
/* If you did a read request, and the result was STATUS_SUCCESS, this function
 * provides the buffer that was read in as well as the number of chars read.
 * The buffer should not be modified or free'd */
char *nse_readbuf(nsock_event nse, int *nbytes) {
  msevent *me = (msevent *)nse;

  if (nbytes)
    *nbytes = fs_length(&(me->iobuf));
  return fs_str(&(me->iobuf));
}
Beispiel #2
0
/* Remember that pcap descriptor is in nonblocking state. */
int do_actual_pcap_read(struct nevent *nse) {
  mspcap *mp = (mspcap *)nse->iod->pcap;
  nsock_pcap npp;
  nsock_pcap *n;
  struct pcap_pkthdr *pkt_header;
  const unsigned char *pkt_data = NULL;
  int rc;

  memset(&npp, 0, sizeof(nsock_pcap));

  nsock_log_debug_all(nse->iod->nsp, "PCAP %s TEST (IOD #%li) (EID #%li)",
                      __func__, nse->iod->id, nse->id);

  assert(fs_length(&(nse->iobuf)) == 0);

  rc = pcap_next_ex(mp->pt, &pkt_header, &pkt_data);
  switch (rc) {
    case 1: /* read good packet  */
#ifdef PCAP_RECV_TIMEVAL_VALID
      npp.ts     = pkt_header->ts;
#else
      /* On these platforms time received from pcap is invalid.
       * It's better to set current time */
      memcpy(&npp.ts, nsock_gettimeofday(), sizeof(struct timeval));
#endif
      npp.len    = pkt_header->len;
      npp.caplen = pkt_header->caplen;
      npp.packet = pkt_data;

      fs_cat(&(nse->iobuf), (char *)&npp, sizeof(npp));
      fs_cat(&(nse->iobuf), (char *)pkt_data, npp.caplen);
      n = (nsock_pcap *)fs_str(&(nse->iobuf));
      n->packet = (unsigned char *)fs_str(&(nse->iobuf)) + sizeof(npp);

      nsock_log_debug_all(nse->iod->nsp,
                          "PCAP %s READ (IOD #%li) (EID #%li) size=%i",
                          __func__, nse->iod->id, nse->id, pkt_header->caplen);
      rc = 1;
      break;

    case 0: /* timeout */
      rc = 0;
      break;

    case -1: /* error */
      fatal("pcap_next_ex() fatal error while reading from pcap: %s\n",
            pcap_geterr(mp->pt));
      break;

    case -2: /* no more packets in savefile (if reading from one) */
    default:
      fatal("Unexpected return code from pcap_next_ex! (%d)\n", rc);
  }

  return rc;
}
Beispiel #3
0
int do_length(const char *filename,uint64_t lv,uint32_t ts,char *ptr) {
	uint32_t inode;
	uint64_t length;
	EAT(ptr,filename,lv,'(');
	GETU32(inode,ptr);
	EAT(ptr,filename,lv,',');
	GETU64(length,ptr);
	EAT(ptr,filename,lv,')');
	return fs_length(ts,inode,length);
}
Beispiel #4
0
void nse_readpcap(nsock_event nsev, const unsigned char **l2_data, size_t *l2_len,
                  const unsigned char **l3_data, size_t *l3_len,
                  size_t *packet_len, struct timeval *ts) {
  struct nevent *nse = (struct nevent *)nsev;
  struct niod  *iod = nse->iod;
  mspcap *mp = (mspcap *)iod->pcap;
  nsock_pcap *n;
  size_t l2l;
  size_t l3l;

  n = (nsock_pcap *)fs_str(&(nse->iobuf));
  if (fs_length(&(nse->iobuf)) < sizeof(nsock_pcap)) {
    if (l2_data)
      *l2_data = NULL;
    if (l2_len)
      *l2_len = 0;
    if (l3_data)
      *l3_data = NULL;
    if (l3_len)
      *l3_len = 0;
    if (packet_len)
      *packet_len = 0;
    return;
  }

  l2l = MIN(mp->l3_offset, n->caplen);
  l3l = MAX(0, n->caplen-mp->l3_offset);

  if (l2_data)
    *l2_data = n->packet;
  if (l2_len)
    *l2_len = l2l;
  if (l3_data)
    *l3_data = (l3l > 0) ? n->packet+l2l : NULL;
  if (l3_len)
    *l3_len = l3l;
  if (packet_len)
    *packet_len = n->len;
  if (ts)
    *ts = n->ts;
  return;
}
Beispiel #5
0
void handle_pcap_read_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
  struct niod *iod = nse->iod;
  mspcap *mp = (mspcap *)iod->pcap;

  switch (status) {
    case NSE_STATUS_TIMEOUT:
      nse->status = NSE_STATUS_TIMEOUT;
      nse->event_done = 1;
      break;

    case NSE_STATUS_CANCELLED:
      nse->status = NSE_STATUS_CANCELLED;
      nse->event_done = 1;
      break;

    case NSE_STATUS_SUCCESS:
      /* check if we already have something read */
      if (fs_length(&(nse->iobuf)) == 0) {
        nse->status = NSE_STATUS_TIMEOUT;
        nse->event_done = 0;
      } else {
        nse->status = NSE_STATUS_SUCCESS; /* we have full buffer */
        nse->event_done = 1;
      }
      break;

    default:
      fatal("Unknown status (%d) for nsock event #%lu", status, nse->id);
  }

  /* If there are no more read events, we are done reading on the socket so we
   * can take it off the descriptor list... */
  if (nse->event_done && mp->pcap_desc >= 0) {
    int ev;

    ev = socket_count_readpcap_dec(iod);
    update_events(iod, ms, EV_NONE, ev);
  }
}
Beispiel #6
0
void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev) {
  int match_r = 0, match_w = 0;
#if HAVE_OPENSSL
  int desire_r = 0, desire_w = 0;
#endif

  nsock_log_debug_all("Processing event %lu (timeout in %ldms, done=%d)",
                      nse->id,
                      (long)TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod),
                      nse->event_done);

  if (!nse->event_done) {
    switch (nse->type) {
      case NSE_TYPE_CONNECT:
      case NSE_TYPE_CONNECT_SSL:
        if (ev != EV_NONE)
          handle_connect_result(nsp, nse, NSE_STATUS_SUCCESS);
        if (event_timedout(nse))
          handle_connect_result(nsp, nse, NSE_STATUS_TIMEOUT);
        break;

      case NSE_TYPE_READ:
        match_r = ev & EV_READ;
        match_w = ev & EV_WRITE;
#if HAVE_OPENSSL
        desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ;
        desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE;
        if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w)))
          handle_read_result(nsp, nse, NSE_STATUS_SUCCESS);
        else
#endif
        if (!nse->iod->ssl && match_r)
          handle_read_result(nsp, nse, NSE_STATUS_SUCCESS);

        if (event_timedout(nse))
          handle_read_result(nsp, nse, NSE_STATUS_TIMEOUT);
        break;

      case NSE_TYPE_WRITE:
        match_r = ev & EV_READ;
        match_w = ev & EV_WRITE;
#if HAVE_OPENSSL
        desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ;
        desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE;
        if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w)))
          handle_write_result(nsp, nse, NSE_STATUS_SUCCESS);
        else
#endif
          if (!nse->iod->ssl && match_w)
            handle_write_result(nsp, nse, NSE_STATUS_SUCCESS);

          if (event_timedout(nse))
            handle_write_result(nsp, nse, NSE_STATUS_TIMEOUT);
          break;

      case NSE_TYPE_TIMER:
        if (event_timedout(nse))
          handle_timer_result(nsp, nse, NSE_STATUS_SUCCESS);
        break;

#if HAVE_PCAP
      case NSE_TYPE_PCAP_READ:{
        nsock_log_debug_all("PCAP iterating %lu", nse->id);

        if (ev & EV_READ) {
          /* buffer empty? check it! */
          if (fs_length(&(nse->iobuf)) == 0)
            do_actual_pcap_read(nse);
        }

        /* if already received something */
        if (fs_length(&(nse->iobuf)) > 0)
          handle_pcap_read_result(nsp, nse, NSE_STATUS_SUCCESS);

        if (event_timedout(nse))
          handle_pcap_read_result(nsp, nse, NSE_STATUS_TIMEOUT);

        #if PCAP_BSD_SELECT_HACK
        /* If event occurred, and we're in BSD_HACK mode, then this event was added
         * to two queues. read_event and pcap_read_event
         * Of course we should destroy it only once.
         * I assume we're now in read_event, so just unlink this event from
         * pcap_read_event */
        if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0
            && nse->event_done
            && evlist == &nsp->read_events) {
          /* event is done, list is read_events and we're in BSD_HACK mode.
           * So unlink event from pcap_read_events */
          update_first_events(nse);
          gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);

          nsock_log_debug_all("PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS",
                              nse->id);
        }
        if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0
            && nse->event_done
            && evlist == &nsp->pcap_read_events) {
          update_first_events(nse);
          gh_list_remove(&nsp->read_events, &nse->nodeq_io);
          nsock_log_debug_all("PCAP NSE #%lu: Removing event from READ_EVENTS",
                              nse->id);
        }
        #endif
        break;
      }
#endif
      default:
        fatal("Event has unknown type (%d)", nse->type);
    }
  }

  if (nse->event_done) {
    /* Security sanity check: don't return a functional SSL iod without
     * setting an SSL data structure. */
    if (nse->type == NSE_TYPE_CONNECT_SSL && nse->status == NSE_STATUS_SUCCESS)
      assert(nse->iod->ssl != NULL);

    nsock_log_debug_all("NSE #%lu: Sending event", nse->id);

    /* WooHoo!  The event is ready to be sent */
    event_dispatch_and_delete(nsp, nse, 1);
  }
}
Beispiel #7
0
void handle_read_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
  unsigned int count;
  char *str;
  int rc, len;
  struct niod *iod = nse->iod;

  if (status == NSE_STATUS_TIMEOUT) {
    nse->event_done = 1;
    if (fs_length(&nse->iobuf) > 0)
      nse->status = NSE_STATUS_SUCCESS;
    else
      nse->status = NSE_STATUS_TIMEOUT;
  } else if (status == NSE_STATUS_CANCELLED) {
    nse->status = status;
    nse->event_done = 1;
  } else if (status == NSE_STATUS_SUCCESS) {
    rc = do_actual_read(ms, nse);
    /* printf("DBG: Just read %d new bytes%s.\n", rc, iod->ssl? "( SSL!)" : ""); */
    if (rc > 0) {
      nse->iod->read_count += rc;
      /* We decide whether we have read enough to return */
      switch (nse->readinfo.read_type) {
        case NSOCK_READ:
          nse->status = NSE_STATUS_SUCCESS;
          nse->event_done = 1;
          break;
        case NSOCK_READBYTES:
          if (fs_length(&nse->iobuf) >= nse->readinfo.num) {
            nse->status = NSE_STATUS_SUCCESS;
            nse->event_done = 1;
          }
          /* else we are not done */
          break;
        case NSOCK_READLINES:
          /* Lets count the number of lines we have ... */
          count = 0;
          len = fs_length(&nse->iobuf) -1;
          str = fs_str(&nse->iobuf);
          for (count=0; len >= 0; len--) {
            if (str[len] == '\n') {
              count++;
              if ((int)count >= nse->readinfo.num)
                break;
            }
          }
          if ((int) count >= nse->readinfo.num) {
            nse->event_done = 1;
            nse->status = NSE_STATUS_SUCCESS;
          }
          /* Else we are not done */
          break;
        default:
          fatal("Unknown operation type (%d)", (int)nse->readinfo.read_type);
      }
    }
  } else {
    fatal("Unknown status (%d)", status);
  }

  /* If there are no more reads for this IOD, we are done reading on the socket
   * so we can take it off the descriptor list ... */
  if (nse->event_done && iod->sd >= 0) {
    int ev = EV_NONE;

#if HAVE_OPENSSL
    if (nse->iod->ssl != NULL)
      ev |= socket_count_dec_ssl_desire(nse);
    else
#endif
      ev |= socket_count_read_dec(nse->iod);
    update_events(nse->iod, ms, EV_NONE, ev);
  }
}
Beispiel #8
0
/* Returns -1 if an error, otherwise the number of newly written bytes */
static int do_actual_read(struct npool *ms, struct nevent *nse) {
  char buf[8192];
  int buflen = 0;
  struct niod *iod = nse->iod;
  int err = 0;
  int max_chunk = NSOCK_READ_CHUNK_SIZE;
  int startlen = fs_length(&nse->iobuf);

  if (nse->readinfo.read_type == NSOCK_READBYTES)
    max_chunk = nse->readinfo.num;

  if (!iod->ssl) {
    do {
      struct sockaddr_storage peer;
      socklen_t peerlen;

      peerlen = sizeof(peer);
      buflen = recvfrom(iod->sd, buf, sizeof(buf), 0, (struct sockaddr *)&peer, &peerlen);

      /* Using recv() was failing, at least on UNIX, for non-network sockets
       * (i.e. stdin) in this case, a read() is done - as on ENOTSOCK we may
       * have a non-network socket */
      if (buflen == -1) {
        if (socket_errno() == ENOTSOCK) {
          peer.ss_family = AF_UNSPEC;
          peerlen = 0;
          buflen = read(iod->sd, buf, sizeof(buf));
        }
      }
      if (buflen == -1) {
        err = socket_errno();
        break;
      }
      if (peerlen > 0) {
        assert(peerlen <= sizeof(iod->peer));
        memcpy(&iod->peer, &peer, peerlen);
        iod->peerlen = peerlen;
      }
      if (buflen > 0) {
        if (fs_cat(&nse->iobuf, buf, buflen) == -1) {
          nse->event_done = 1;
          nse->status = NSE_STATUS_ERROR;
          nse->errnum = ENOMEM;
          return -1;
        }

        /* Sometimes a service just spews and spews data.  So we return after a
         * somewhat large amount to avoid monopolizing resources and avoid DOS
         * attacks. */
        if (fs_length(&nse->iobuf) > max_chunk)
          return fs_length(&nse->iobuf) - startlen;

        /* No good reason to read again if we we were successful in the read but
         * didn't fill up the buffer.  Especially for UDP, where we want to
         * return only one datagram at a time. The consistency of the above
         * assignment of iod->peer depends on not consolidating more than one
         * UDP read buffer. */
        if (buflen > 0 && buflen < sizeof(buf))
          return fs_length(&nse->iobuf) - startlen;
      }
    } while (buflen > 0 || (buflen == -1 && err == EINTR));

    if (buflen == -1) {
      if (err != EINTR && err != EAGAIN) {
        nse->event_done = 1;
        nse->status = NSE_STATUS_ERROR;
        nse->errnum = err;
        return -1;
      }
    }
  } else {
#if HAVE_OPENSSL
    /* OpenSSL read */
    while ((buflen = SSL_read(iod->ssl, buf, sizeof(buf))) > 0) {

      if (fs_cat(&nse->iobuf, buf, buflen) == -1) {
        nse->event_done = 1;
        nse->status = NSE_STATUS_ERROR;
        nse->errnum = ENOMEM;
        return -1;
      }

      /* Sometimes a service just spews and spews data.  So we return
       * after a somewhat large amount to avoid monopolizing resources
       * and avoid DOS attacks. */
      if (fs_length(&nse->iobuf) > max_chunk)
        return fs_length(&nse->iobuf) - startlen;
    }

    if (buflen == -1) {
      err = SSL_get_error(iod->ssl, buflen);
      if (err == SSL_ERROR_WANT_READ) {
        int evclr;

        evclr = socket_count_dec_ssl_desire(nse);
        socket_count_read_inc(iod);
        update_events(iod, ms, EV_READ, evclr);
        nse->sslinfo.ssl_desire = err;
      } else if (err == SSL_ERROR_WANT_WRITE) {
        int evclr;

        evclr = socket_count_dec_ssl_desire(nse);
        socket_count_write_inc(iod);
        update_events(iod, ms, EV_WRITE, evclr);
        nse->sslinfo.ssl_desire = err;
      } else {
        /* Unexpected error */
        nse->event_done = 1;
        nse->status = NSE_STATUS_ERROR;
        nse->errnum = EIO;
        nsock_log_info("SSL_read() failed for reason %s on NSI %li",
                       ERR_error_string(err, NULL), iod->id);
        return -1;
      }
    }
#endif /* HAVE_OPENSSL */
  }

  if (buflen == 0) {
    nse->event_done = 1;
    nse->eof = 1;
    if (fs_length(&nse->iobuf) > 0) {
      nse->status = NSE_STATUS_SUCCESS;
      return fs_length(&nse->iobuf) - startlen;
    } else {
      nse->status = NSE_STATUS_EOF;
      return 0;
    }
  }

  return fs_length(&nse->iobuf) - startlen;
}
Beispiel #9
0
void handle_write_result(struct npool *ms, struct nevent *nse, enum nse_status status) {
  int bytesleft;
  char *str;
  int res;
  int err;
  struct niod *iod = nse->iod;

  if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) {
    nse->event_done = 1;
    nse->status = status;
  } else if (status == NSE_STATUS_SUCCESS) {
    str = fs_str(&nse->iobuf) + nse->writeinfo.written_so_far;
    bytesleft = fs_length(&nse->iobuf) - nse->writeinfo.written_so_far;
    if (nse->writeinfo.written_so_far > 0)
      assert(bytesleft > 0);
#if HAVE_OPENSSL
    if (iod->ssl)
      res = SSL_write(iod->ssl, str, bytesleft);
    else
#endif
      if (nse->writeinfo.dest.ss_family == AF_UNSPEC)
        res = send(nse->iod->sd, str, bytesleft, 0);
      else
        res = sendto(nse->iod->sd, str, bytesleft, 0, (struct sockaddr *)&nse->writeinfo.dest, (int)nse->writeinfo.destlen);
    if (res == bytesleft) {
      nse->event_done = 1;
      nse->status = NSE_STATUS_SUCCESS;
    } else if (res >= 0) {
      nse->writeinfo.written_so_far += res;
    } else {
      assert(res == -1);
      if (iod->ssl) {
#if HAVE_OPENSSL
        err = SSL_get_error(iod->ssl, res);
        if (err == SSL_ERROR_WANT_READ) {
          int evclr;

          evclr = socket_count_dec_ssl_desire(nse);
          socket_count_read_inc(iod);
          update_events(iod, ms, EV_READ, evclr);
          nse->sslinfo.ssl_desire = err;
        } else if (err == SSL_ERROR_WANT_WRITE) {
          int evclr;

          evclr = socket_count_dec_ssl_desire(nse);
          socket_count_write_inc(iod);
          update_events(iod, ms, EV_WRITE, evclr);
          nse->sslinfo.ssl_desire = err;
        } else {
          /* Unexpected error */
          nse->event_done = 1;
          nse->status = NSE_STATUS_ERROR;
          nse->errnum = EIO;
        }
#endif
      } else {
        err = socket_errno();
        if (errcode_is_failure(err)) {
          nse->event_done = 1;
          nse->status = NSE_STATUS_ERROR;
          nse->errnum = err;
        }
      }
    }

    if (res >= 0)
      nse->iod->write_count += res;
  }

  if (nse->event_done && nse->iod->sd != -1) {
    int ev = EV_NONE;

#if HAVE_OPENSSL
    if (nse->iod->ssl != NULL)
      ev |= socket_count_dec_ssl_desire(nse);
    else
#endif
      ev |= socket_count_write_dec(nse->iod);
    update_events(nse->iod, ms, EV_NONE, ev);
  }
}