diff --git a/nsock/include/nsock_config.h.in b/nsock/include/nsock_config.h.in index 455d87ede..ee9c0206e 100644 --- a/nsock/include/nsock_config.h.in +++ b/nsock/include/nsock_config.h.in @@ -90,3 +90,4 @@ #undef HAVE_KQUEUE #undef PCAP_NETMASK_UNKNOWN +#undef HAVE_PCAP_SET_IMMEDIATE_MODE diff --git a/nsock/src/configure b/nsock/src/configure index 1d7a1aa39..e0fb899f3 100755 --- a/nsock/src/configure +++ b/nsock/src/configure @@ -3639,7 +3639,23 @@ if test "$with_libpcap" != "no" -a "$have_libpcap" = "no"; then LIBPCAP_LIB=${top_nmap_srcdir}/libpcap LIBPCAP_LIBS=${LIBPCAP_LIB}/libpcap.a have_libpcap=yes + +$as_echo "#define HAVE_PCAP_SET_IMMEDIATE_MODE 1" >>confdefs.h + +else + for ac_func in pcap_set_immediate_mode +do : + ac_fn_c_check_func "$LINENO" "pcap_set_immediate_mode" "ac_cv_func_pcap_set_immediate_mode" +if test "x$ac_cv_func_pcap_set_immediate_mode" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PCAP_SET_IMMEDIATE_MODE 1 +_ACEOF + fi +done + +fi + if test "$have_libpcap" != "no"; then $as_echo "#define HAVE_PCAP 1" >>confdefs.h diff --git a/nsock/src/configure.ac b/nsock/src/configure.ac index a92d01a68..47b7e2608 100644 --- a/nsock/src/configure.ac +++ b/nsock/src/configure.ac @@ -161,7 +161,11 @@ if test "$with_libpcap" != "no" -a "$have_libpcap" = "no"; then LIBPCAP_LIB=${top_nmap_srcdir}/libpcap LIBPCAP_LIBS=${LIBPCAP_LIB}/libpcap.a have_libpcap=yes + AC_DEFINE(HAVE_PCAP_SET_IMMEDIATE_MODE, 1, [Included libpcap has pcap_set_immediate_mode]) +else + AC_CHECK_FUNCS([pcap_set_immediate_mode]) fi + if test "$have_libpcap" != "no"; then AC_DEFINE(HAVE_PCAP, 1, [libpcap is available]) if test "${LIBPCAP_INC+set}" = "set"; then diff --git a/nsock/src/nsock_pcap.c b/nsock/src/nsock_pcap.c index 18bd41b1b..ec554b159 100644 --- a/nsock/src/nsock_pcap.c +++ b/nsock/src/nsock_pcap.c @@ -197,23 +197,6 @@ static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl) { return (offset); } -static int nsock_pcap_try_open(struct npool *nsp, mspcap *mp, const char *dev, - int snaplen, int promisc, int timeout_ms, - char *errbuf) { - /* TODO: Convert from pcap_open_live to pcap_create and set appropriate options. - * Maybe expose an API for setting said options. We can't assume that all - * Nsock apps will want the same options that Nmap wants, especially the - * options Nmap wants for port scanning. - */ - mp->pt = pcap_open_live(dev, snaplen, promisc, timeout_ms, errbuf); - if (!mp->pt) { - nsock_log_error("pcap_open_live(%s, %d, %d, %d) failed with error: %s", - dev, snaplen, promisc, timeout_ms, errbuf); - return -1; - } - return 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 @@ -270,23 +253,54 @@ int nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, const char *pcap_device, "(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("Will wait %d seconds then retry.", 4 * failed); - sleep(4 * failed); - } - } while (rc && failed < PCAP_OPEN_MAX_RETRIES); - - if (rc) { - nsock_log_error("pcap_open_live(%s, %d, %d, %d) failed %d times.", - pcap_device, snaplen, promisc, to_ms, failed); +#ifdef __amigaos__ + // Amiga doesn't have pcap_create + // TODO: Does Nmap still work on Amiga? + mp->pt = pcap_open_live(pcap_device, snaplen, promisc, to_ms, errbuf); + if (!mp->pt) { + nsock_log_error("pcap_open_live(%s, %d, %d, %d) failed with error: %s", + pcap_device, snaplen, promisc, to_ms, errbuf); nsock_log_error(PCAP_FAILURE_EXPL_MESSAGE); nsock_log_error("Can't open pcap! Are you root?"); return -1; } +#else + mp->pt = pcap_create(pcap_device, errbuf); + if (!mp->pt) { + nsock_log_error("pcap_create(%s) failed with error: %s", pcap_device, errbuf); + nsock_log_error(PCAP_FAILURE_EXPL_MESSAGE); + nsock_log_error("Can't open pcap! Are you root?"); + return -1; + } + +#define MY_PCAP_SET(func, p_t, val) do {\ + failed = func(p_t, val);\ + if (failed) {\ + nsock_log_error(#func "(%d) FAILED: %d.", val, failed);\ + pcap_close(p_t);\ + return -1;\ + }\ +} while(0); + + MY_PCAP_SET(pcap_set_snaplen, mp->pt, snaplen); + MY_PCAP_SET(pcap_set_promisc, mp->pt, promisc); + MY_PCAP_SET(pcap_set_timeout, mp->pt, to_ms); +#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE + MY_PCAP_SET(pcap_set_immediate_mode, mp->pt, 1); +#endif + + failed = pcap_activate(mp->pt); + if (failed < 0) { + // PCAP error + nsock_log_error("pcap_activate(%s) FAILED: %s.", pcap_device, pcap_geterr(mp->pt)); + pcap_close(mp->pt); + return -1; + } + else if (failed > 0) { + // PCAP warning, report but assume it'll still work + nsock_log_error("pcap_activate(%s) WARNING: %s.", pcap_device, pcap_geterr(mp->pt)); + } +#endif /* not __amigaos__ */ rc = nsock_pcap_set_filter(ms, mp->pt, pcap_device, bpf); if (rc) @@ -308,18 +322,21 @@ int nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, const char *pcap_device, #endif mp->readsd_count = 0; +#ifndef HAVE_PCAP_SET_IMMEDIATE_MODE + /* This is already handled by pcap_set_immediate_mode if available */ +#ifdef BIOCIMMEDIATE /* 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 #endif /* Set device non-blocking */