Esempio n. 1
0
/* Create the actual socket (nse->iod->sd) underlying the iod. This unblocks the
 * socket, binds to the localaddr address, sets IP options, and sets the
 * broadcast flag. Trying to change these functions after making this call will
 * not have an effect. This function needs to be called before you try to read
 * or write on the iod. */
static int nsock_make_socket(struct npool *ms, struct niod *iod, int family, int type, int proto) {

  /* inheritable_socket is from nbase */
  iod->sd = (int)inheritable_socket(family, type, proto);
  if (iod->sd == -1) {
    nsock_log_error("Socket trouble: %s", socket_strerror(socket_errno()));
    return -1;
  }

  unblock_socket(iod->sd);

  iod->lastproto = proto;

  if (iod->locallen)
    mksock_bind_addr(ms, iod);

  if (iod->ipoptslen && family == AF_INET)
    mksock_set_ipopts(ms, iod);

  if (ms->device)
    mksock_bind_device(ms, iod);

  if (ms->broadcast && type != SOCK_STREAM)
    mksock_set_broadcast(ms, iod);

  /* mksock_* functions can raise warnings/errors
   * but we don't let them stop us for now. */
  return iod->sd;
}
Esempio n. 2
0
int nsock_pool_set_proxychain(nsock_pool nspool, nsock_proxychain chain) {
  struct npool *nsp = (struct npool *)nspool;

  if (nsp && nsp->px_chain) {
    nsock_log_error("Invalid call. Existing proxychain on this nsock_pool");
    return -1;
  }

  nsp->px_chain = (struct proxy_chain *)chain;
  return 1;
}
Esempio n. 3
0
static int nsock_pcap_try_open(struct npool *nsp, mspcap *mp, const char *dev,
                               int snaplen, int promisc, int timeout_ms,
                               char *errbuf) {
    mp->pt = pcap_open_live(dev, snaplen, promisc, timeout_ms, errbuf);
    if (!mp->pt) {
      nsock_log_error(nsp, "pcap_open_live(%s, %d, %d, %d) failed with error: %s",
                      dev, snaplen, promisc, timeout_ms, errbuf);
      return -1;
    }
    return 0;
}
Esempio n. 4
0
static int nsock_pcap_set_filter(struct npool *nsp, pcap_t *pt, const char *device,
                                 const char *bpf) {
  struct bpf_program fcode;
  int rc;

  rc = pcap_compile(pt, &fcode, (char *)bpf, 1, 0);
  if (rc) {
    nsock_log_error(nsp, "Error compiling pcap filter: %s", pcap_geterr(pt));
    return rc;
  }

  rc = pcap_setfilter(pt, &fcode);
  if (rc) {
    nsock_log_error(nsp, "Failed to set the pcap filter: %s", pcap_geterr(pt));
    return rc;
  }

  pcap_freecode(&fcode);
  return 0;
}
Esempio n. 5
0
static int mksock_set_ipopts(struct npool *ms, struct niod *iod) {
  int rc;

  errno = 0;
  rc = setsockopt(iod->sd, IPPROTO_IP, IP_OPTIONS, (const char *)iod->ipopts,
                  iod->ipoptslen);
  if (rc == -1) {
    int err = socket_errno();

    nsock_log_error("Setting of IP options failed (IOD #%li): %s (%d)",
                    iod->id, socket_strerror(err), err);
  }
  return 0;
}
Esempio n. 6
0
static int mksock_bind_addr(struct npool *ms, struct niod *iod) {
  int rc;
  int one = 1;

  rc = setsockopt(iod->sd, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one));
  if (rc == -1) {
    int err = socket_errno();

    nsock_log_error("Setting of SO_REUSEADDR failed (#%li): %s (%d)", iod->id,
                    socket_strerror(err), err);
  }

  nsock_log_info("Binding to %s (IOD #%li)", get_localaddr_string(iod), iod->id);
  rc = bind(iod->sd, (struct sockaddr *)&iod->local, (int) iod->locallen);
  if (rc == -1) {
    int err = socket_errno();

    nsock_log_error("Bind to %s failed (IOD #%li): %s (%d)",
                    get_localaddr_string(iod), iod->id,
                    socket_strerror(err), err);
  }
  return 0;
}
Esempio n. 7
0
static int mksock_set_broadcast(struct npool *ms, struct niod *iod) {
  int rc;
  int one = 1;

  rc = setsockopt(iod->sd, SOL_SOCKET, SO_BROADCAST,
                  (const char *)&one, sizeof(one));
  if (rc == -1) {
    int err = socket_errno();

    nsock_log_error("Setting of SO_BROADCAST failed (IOD #%li): %s (%d)",
                    iod->id, socket_strerror(err), err);
  }
  return 0;
}
Esempio n. 8
0
static int mksock_bind_device(struct npool *ms, struct niod *iod) {
  int rc;

  rc = socket_bindtodevice(iod->sd, ms->device);
  if (!rc) {
    int err = socket_errno();

    if (err != EPERM)
      nsock_log_error("Setting of SO_BINDTODEVICE failed (IOD #%li): %s (%d)",
                      iod->id, socket_strerror(err), err);
    else
      nsock_log_debug_all("Setting of SO_BINDTODEVICE failed (IOD #%li): %s (%d)",
                          iod->id, socket_strerror(err), err);
  }
  return 0;
}
Esempio n. 9
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. 10
0
int kqueue_loop(mspool *nsp, int msec_timeout) {
  int results_left = 0;
  int event_msecs; /* msecs before an event goes off */
  int combined_msecs;
  struct timespec ts, *ts_p;
  int sock_err = 0;
  struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data;

  assert(msec_timeout >= -1);

  if (nsp->events_pending == 0)
    return 0; /* No need to wait on 0 events ... */


  if (gh_list_count(&nsp->active_iods) > kinfo->evlen) {
    kinfo->evlen = gh_list_count(&nsp->active_iods) * 2;
    kinfo->events = (struct kevent *)safe_realloc(kinfo->events, kinfo->evlen * sizeof(struct kevent));
  }

  do {
    msevent *nse;

    nsock_log_debug_all(nsp, "wait for events");

    nse = next_expirable_event(nsp);
    if (!nse)
      event_msecs = -1; /* None of the events specified a timeout */
    else
      event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* Force a low timeout when capturing packets on systems where
     * the pcap descriptor is not select()able. */
    if (gh_list_count(&nsp->pcap_read_events) > 0)
      if (event_msecs > PCAP_POLL_INTERVAL)
        event_msecs = PCAP_POLL_INTERVAL;
#endif
#endif

    /* We cast to unsigned because we want -1 to be very high (since it means no
     * timeout) */
    combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);

    /* Set up the timeval pointer we will give to kevent() */
    memset(&ts, 0, sizeof(struct timespec));
    if (combined_msecs >= 0) {
      ts.tv_sec = combined_msecs / 1000;
      ts.tv_nsec = (combined_msecs % 1000) * 1000000L;
      ts_p = &ts;
    } else {
      ts_p = NULL;
    }

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* do non-blocking read on pcap devices that doesn't support select()
     * If there is anything read, just leave this loop. */
    if (pcap_read_on_nonselect(nsp)) {
      /* okay, something was read. */
    } else
#endif
#endif
    {
      results_left = kevent(kinfo->kqfd, NULL, 0, kinfo->events, kinfo->evlen, ts_p);
      if (results_left == -1)
        sock_err = socket_errno();
    }

    gettimeofday(&nsock_tod, NULL); /* Due to kevent delay */
  } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */

  if (results_left == -1 && sock_err != EINTR) {
    nsock_log_error(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
    nsp->errnum = sock_err;
    return -1;
  }

  iterate_through_event_lists(nsp, results_left);

  return 1;
}
Esempio n. 11
0
int select_loop(mspool *nsp, int msec_timeout) {
  int results_left = 0;
  int event_msecs; /* msecs before an event goes off */
  int combined_msecs;
  int sock_err = 0;
  struct timeval select_tv;
  struct timeval *select_tv_p;
  struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;

  assert(msec_timeout >= -1);

  if (nsp->events_pending == 0)
    return 0; /* No need to wait on 0 events ... */

  do {
    nsock_log_debug_all(nsp, "wait for events");

    if (nsp->next_ev.tv_sec == 0)
      event_msecs = -1; /* None of the events specified a timeout */
    else
      event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* Force a low timeout when capturing packets on systems where
     * the pcap descriptor is not select()able. */
    if (GH_LIST_COUNT(&nsp->pcap_read_events))
      if (event_msecs > PCAP_POLL_INTERVAL)
        event_msecs = PCAP_POLL_INTERVAL;
#endif
#endif

    /* We cast to unsigned because we want -1 to be very high (since it means no
     * timeout) */
    combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);

    /* Set up the timeval pointer we will give to select() */
    memset(&select_tv, 0, sizeof(select_tv));
    if (combined_msecs > 0) {
      select_tv.tv_sec = combined_msecs / 1000;
      select_tv.tv_usec = (combined_msecs % 1000) * 1000;
      select_tv_p = &select_tv;
    } else if (combined_msecs == 0) {
      /* we want the tv_sec and tv_usec to be zero but they already are from bzero */
      select_tv_p = &select_tv;
    } else {
      assert(combined_msecs == -1);
      select_tv_p = NULL;
    }

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* do non-blocking read on pcap devices that doesn't support select()
     * If there is anything read, just leave this loop. */
    if (pcap_read_on_nonselect(nsp)) {
      /* okay, something was read. */
    } else
#endif
#endif
    {
      /* Set up the descriptors for select */
      sinfo->fds_results_r = sinfo->fds_master_r;
      sinfo->fds_results_w = sinfo->fds_master_w;
      sinfo->fds_results_x = sinfo->fds_master_x;

      results_left = fselect(sinfo->max_sd + 1, &sinfo->fds_results_r,
                             &sinfo->fds_results_w, &sinfo->fds_results_x, select_tv_p);

      if (results_left == -1)
        sock_err = socket_errno();
    }

    gettimeofday(&nsock_tod, NULL); /* Due to select delay */
  } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */

  if (results_left == -1 && sock_err != EINTR) {
    nsock_log_error(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
    nsp->errnum = sock_err;
    return -1;
  }

  iterate_through_event_lists(nsp);

  return 1;
}
Esempio n. 12
0
int poll_loop(struct npool *nsp, int msec_timeout) {
  int results_left = 0;
  int event_msecs; /* msecs before an event goes off */
  int combined_msecs;
  int sock_err = 0;
  struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data;

  assert(msec_timeout >= -1);

  if (nsp->events_pending == 0)
    return 0; /* No need to wait on 0 events ... */

  do {
    struct nevent *nse;

    nsock_log_debug_all(nsp, "wait for events");

    nse = next_expirable_event(nsp);
    if (!nse)
      event_msecs = -1; /* None of the events specified a timeout */
    else
      event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* Force a low timeout when capturing packets on systems where
     * the pcap descriptor is not select()able. */
    if (gh_list_count(&nsp->pcap_read_events) > 0)
      if (event_msecs > PCAP_POLL_INTERVAL)
        event_msecs = PCAP_POLL_INTERVAL;
#endif
#endif

    /* We cast to unsigned because we want -1 to be very high (since it means no
     * timeout) */
    combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* do non-blocking read on pcap devices that doesn't support select()
     * If there is anything read, just leave this loop. */
    if (pcap_read_on_nonselect(nsp)) {
      /* okay, something was read. */
    } else
#endif
#endif
    {
      results_left = Poll(pinfo->events, pinfo->max_fd + 1, combined_msecs);
      if (results_left == -1)
        sock_err = socket_errno();
    }

    gettimeofday(&nsock_tod, NULL); /* Due to poll delay */
  } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */

  if (results_left == -1 && sock_err != EINTR) {
    nsock_log_error(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
    nsp->errnum = sock_err;
    return -1;
  }

  iterate_through_event_lists(nsp);

  return 1;
}
Esempio n. 13
0
/* Convert new nsiod to pcap descriptor. Other parameters have
 * the same meaning as for pcap_open_live in pcap(3).
 *   device   : pcap-style device name
 *   snaplen  : size of packet to be copied to handler
 *   promisc  : whether to open device in promiscuous mode
 *   bpf_fmt   : berkeley filter
 * return value: NULL if everything was okay, or error string
 * if error occurred. */
int nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, const char *pcap_device,
                    int snaplen, int promisc, const char *bpf_fmt, ...) {
  struct niod *nsi = (struct niod *)nsiod;
  struct npool *ms = (struct npool *)nsp;
  mspcap *mp = (mspcap *)nsi->pcap;
  char errbuf[PCAP_ERRBUF_SIZE];
  char bpf[4096];
  va_list ap;
  int failed, datalink;
  int rc;

#ifdef PCAP_CAN_DO_SELECT
#if PCAP_BSD_SELECT_HACK
  /* MacOsX reports error if to_ms is too big (like INT_MAX) with error
   * FAILED. Reported error: BIOCSRTIMEOUT: Invalid argument
   * INT_MAX/6 (=357913941) seems to be working... */
  int to_ms = 357913941;
#else
  int to_ms = 200;
#endif /* PCAP_BSD_SELECT_HACK */

#else
  int to_ms = 1;
#endif

  gettimeofday(&nsock_tod, NULL);

  if (mp) {
    nsock_log_error(ms, "This nsi already has pcap device opened");
    return -1;
  }

  mp = (mspcap *)safe_zalloc(sizeof(mspcap));
  nsi->pcap = (void *)mp;

  va_start(ap, bpf_fmt);
  rc = Vsnprintf(bpf, sizeof(bpf), bpf_fmt, ap);
  va_end(ap);

  if (rc >= (int)sizeof(bpf)) {
    nsock_log_error(ms, "Too-large bpf filter argument");
    return -1;
  }

  nsock_log_info(ms, "PCAP requested on device '%s' with berkeley filter '%s' "
                 "(promisc=%i snaplen=%i to_ms=%i) (IOD #%li)",
                 pcap_device,bpf, promisc, snaplen, to_ms, nsi->id);

  failed = 0;
  do {
    rc = nsock_pcap_try_open(ms, mp, pcap_device, snaplen, promisc, to_ms, errbuf);
    if (rc) {
      failed++;
      nsock_log_error(ms, "Will wait %d seconds then retry.", 4 * failed);
      sleep(4 * failed);
    }
  } while (rc && failed < PCAP_OPEN_MAX_RETRIES);

  if (rc) {
    nsock_log_error(ms, "pcap_open_live(%s, %d, %d, %d) failed %d times.",
                    pcap_device, snaplen, promisc, to_ms, failed);
    nsock_log_error(ms, PCAP_FAILURE_EXPL_MESSAGE);
    nsock_log_error(ms, "Can't open pcap! Are you root?");
    return -1;
  }

  rc = nsock_pcap_set_filter(ms, mp->pt, pcap_device, bpf);
  if (rc)
    return rc;

#ifdef WIN32
  /* We want any responses back ASAP */
  pcap_setmintocopy(mp->pt, 1);
#endif

  mp->l3_offset = nsock_pcap_get_l3_offset(mp->pt, &datalink);
  mp->snaplen = snaplen;
  mp->datalink = datalink;
  mp->pcap_device = strdup(pcap_device);
#ifdef PCAP_CAN_DO_SELECT
  mp->pcap_desc = pcap_get_selectable_fd(mp->pt);
#else
  mp->pcap_desc = -1;
#endif
  mp->readsd_count = 0;

  /* Without setting this ioctl, some systems (BSDs, though it depends on the
   * release) will buffer packets in non-blocking mode and only return them in a
   * bunch when the buffer is full. Setting the ioctl makes each one be
   * delivered immediately. This is how Linux works by default. See the comments
   * surrounding the setting of BIOCIMMEDIATE in libpcap/pcap-bpf.c. */
#ifdef BIOCIMMEDIATE
  if (mp->pcap_desc != -1) {
    int immediate = 1;

    if (ioctl(mp->pcap_desc, BIOCIMMEDIATE, &immediate) < 0)
      fatal("Cannot set BIOCIMMEDIATE on pcap descriptor");
  }
#endif

  /* Set device non-blocking */
  rc = pcap_setnonblock(mp->pt, 1, errbuf);
  if (rc) {

    /* I can't do select() on pcap!
     * blocking + no_select is fatal */
#ifndef PCAP_BSD_SELECT_HACK
    if (mp->pcap_desc < 0)
#endif
    {
      nsock_log_error(ms, "Failed to set pcap descriptor on device %s "
                      "to nonblocking mode: %s", pcap_device, errbuf);
      return -1;
    }
    /* in other case, we can accept blocking pcap */
    nsock_log_info(ms, "Failed to set pcap descriptor on device %s "
                   "to nonblocking state: %s", pcap_device, errbuf);
  }

  if (ms->loglevel <= NSOCK_LOG_INFO) {
    #if PCAP_BSD_SELECT_HACK
      int bsd_select_hack = 1;
    #else
      int bsd_select_hack = 0;
    #endif

    #if PCAP_RECV_TIMEVAL_VALID
      int recv_timeval_valid = 1;
    #else
      int recv_timeval_valid = 0;
    #endif

    nsock_log_info(ms, "PCAP created successfully on device '%s' "
                   "(pcap_desc=%i bsd_hack=%i to_valid=%i l3_offset=%i) (IOD #%li)",
                   pcap_device, mp->pcap_desc, bsd_select_hack,
                   recv_timeval_valid, mp->l3_offset, nsi->id);
  }
  return 0;
}