mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Switch from pcap_next to pcap_next_ex to check for errors
This change supports #1394. When the network goes down, Nmap ought to stop instead of slowing to an infinite crawl.
This commit is contained in:
@@ -955,7 +955,7 @@ int my_pcap_get_selectable_fd(pcap_t *p) {
|
||||
fd is selectable? If not, it's possible for the fd to become selectable, then
|
||||
for pcap_dispatch to buffer two or more frames, and return only the first one
|
||||
Because select doesn't know about pcap's buffer, the fd does not become
|
||||
selectable again, even though another pcap_next would succeed. On these
|
||||
selectable again, even though another pcap_next_ex would succeed. On these
|
||||
platforms, we must do a non-blocking read from the fd before doing a select
|
||||
on the fd.
|
||||
|
||||
@@ -4172,7 +4172,7 @@ int datalink_offset(int datalink)
|
||||
the function returns 0 and the output parameters are undefined. */
|
||||
static int read_reply_pcap(pcap_t *pd, long to_usec,
|
||||
bool (*accept_callback)(const unsigned char *, const struct pcap_pkthdr *, int, size_t),
|
||||
unsigned char **p, struct pcap_pkthdr *head, struct timeval *rcvdtime,
|
||||
const unsigned char **p, struct pcap_pkthdr **head, struct timeval *rcvdtime,
|
||||
int *datalink, size_t *offset)
|
||||
{
|
||||
static int warning = 0;
|
||||
@@ -4207,6 +4207,7 @@ static int read_reply_pcap(pcap_t *pd, long to_usec,
|
||||
do {
|
||||
|
||||
*p = NULL;
|
||||
int pcap_status = 0;
|
||||
/* It may be that protecting this with !pcap_selectable_fd_one_to_one is not
|
||||
necessary, that it is always safe to do a nonblocking read in this way on
|
||||
all platforms. But I have only tested it on Solaris. */
|
||||
@@ -4217,22 +4218,32 @@ static int read_reply_pcap(pcap_t *pd, long to_usec,
|
||||
assert(nonblock == 0);
|
||||
rc = pcap_setnonblock(pd, 1, NULL);
|
||||
assert(rc == 0);
|
||||
*p = (u8 *) pcap_next(pd, head);
|
||||
pcap_status = pcap_next_ex(pd, head, p);
|
||||
rc = pcap_setnonblock(pd, nonblock, NULL);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
if (*p == NULL) {
|
||||
/* Nonblocking pcap_next didn't get anything. */
|
||||
if (pcap_status == PCAP_ERROR) {
|
||||
// TODO: Gracefully end the scan.
|
||||
netutil_fatal("Error from pcap_next_ex: %s\n", pcap_geterr(pd));
|
||||
}
|
||||
|
||||
if (pcap_status == 0 || *p == NULL) {
|
||||
/* Nonblocking pcap_next_ex didn't get anything. */
|
||||
if (pcap_select(pd, to_usec) == 0)
|
||||
timedout = 1;
|
||||
else
|
||||
*p = (u8 *) pcap_next(pd, head);
|
||||
pcap_status = pcap_next_ex(pd, head, p);
|
||||
}
|
||||
|
||||
if (*p != NULL && accept_callback(*p, head, *datalink, *offset)) {
|
||||
if (pcap_status == PCAP_ERROR) {
|
||||
// TODO: Gracefully end the scan.
|
||||
netutil_fatal("Error from pcap_next_ex: %s\n", pcap_geterr(pd));
|
||||
}
|
||||
|
||||
if (pcap_status == 1 && *p != NULL && accept_callback(*p, *head, *datalink, *offset)) {
|
||||
break;
|
||||
} else if (*p == NULL) {
|
||||
} else if (pcap_status == 0 || *p == NULL) {
|
||||
/* Should we timeout? */
|
||||
if (to_usec == 0) {
|
||||
timedout = 1;
|
||||
@@ -4264,9 +4275,9 @@ static int read_reply_pcap(pcap_t *pd, long to_usec,
|
||||
gettimeofday(&tv_end, NULL);
|
||||
*rcvdtime = tv_end;
|
||||
#else
|
||||
rcvdtime->tv_sec = head->ts.tv_sec;
|
||||
rcvdtime->tv_usec = head->ts.tv_usec;
|
||||
assert(head->ts.tv_sec);
|
||||
rcvdtime->tv_sec = (*head)->ts.tv_sec;
|
||||
rcvdtime->tv_usec = (*head)->ts.tv_usec;
|
||||
assert((*head)->ts.tv_sec);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4308,8 +4319,8 @@ int read_arp_reply_pcap(pcap_t *pd, u8 *sendermac,
|
||||
struct in_addr *senderIP, long to_usec,
|
||||
struct timeval *rcvdtime,
|
||||
void (*trace_callback)(int, const u8 *, u32, struct timeval *)) {
|
||||
unsigned char *p;
|
||||
struct pcap_pkthdr head;
|
||||
const unsigned char *p;
|
||||
struct pcap_pkthdr *head;
|
||||
int datalink;
|
||||
size_t offset;
|
||||
int rc;
|
||||
@@ -4360,8 +4371,8 @@ int read_ns_reply_pcap(pcap_t *pd, u8 *sendermac,
|
||||
struct sockaddr_in6 *senderIP, long to_usec,
|
||||
struct timeval *rcvdtime,
|
||||
void (*trace_callback)(int, const u8 *, u32, struct timeval *)) {
|
||||
unsigned char *p;
|
||||
struct pcap_pkthdr head;
|
||||
const unsigned char *p;
|
||||
struct pcap_pkthdr *head;
|
||||
int datalink;
|
||||
size_t offset;
|
||||
int rc;
|
||||
|
||||
57
tcpip.cc
57
tcpip.cc
@@ -1551,8 +1551,9 @@ char *readipv4_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
struct timeval *rcvdtime, struct link_header *linknfo, bool validate) {
|
||||
unsigned int offset = 0;
|
||||
struct pcap_pkthdr head;
|
||||
char *p;
|
||||
struct pcap_pkthdr *head;
|
||||
const unsigned char *p;
|
||||
int pcap_status = 0;
|
||||
int datalink;
|
||||
int timedout = 0;
|
||||
struct timeval tv_start, tv_end;
|
||||
@@ -1651,18 +1652,22 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
p = (char *) pcap_next(pd, &head);
|
||||
if (head.caplen == 0) {
|
||||
pcap_status = pcap_next_ex(pd, &head, &p);
|
||||
if (pcap_status == 0) {
|
||||
/* Lets sleep a brief time and try again to increase the chance of seeing
|
||||
a real packet ... */
|
||||
usleep(500000);
|
||||
p = (char *) pcap_next(pd, &head);
|
||||
pcap_status = pcap_next_ex(pd, &head, &p);
|
||||
}
|
||||
if (head.caplen > 100000) {
|
||||
fatal("FATAL: %s: bogus caplen from libpcap (%d) on interface type %d", __func__, head.caplen, datalink);
|
||||
if (pcap_status != 1 || !head) {
|
||||
// No packet captured
|
||||
fatal("FATAL: Unknown datalink type (%d).", datalink);
|
||||
}
|
||||
error("FATAL: Unknown datalink type (%d). Caplen: %d; Packet:", datalink, head.caplen);
|
||||
nmap_hexdump((unsigned char *) p, head.caplen);
|
||||
if (head->caplen > 100000 || !p) {
|
||||
fatal("FATAL: %s: bogus caplen from libpcap (%d) on interface type %d", __func__, head->caplen, datalink);
|
||||
}
|
||||
error("FATAL: Unknown datalink type (%d). Caplen: %d; Packet:", datalink, head->caplen);
|
||||
nmap_hexdump(p, head->caplen);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -1673,6 +1678,7 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
do {
|
||||
|
||||
p = NULL;
|
||||
pcap_status = 0;
|
||||
/* It may be that protecting this with !pcap_selectable_fd_one_to_one is not
|
||||
necessary, that it is always safe to do a nonblocking read in this way on
|
||||
all platforms. But I have only tested it on Solaris. */
|
||||
@@ -1683,21 +1689,32 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
assert(nonblock == 0);
|
||||
rc = pcap_setnonblock(pd, 1, NULL);
|
||||
assert(rc == 0);
|
||||
p = (char *) pcap_next(pd, &head);
|
||||
pcap_status = pcap_next_ex(pd, &head, &p);
|
||||
rc = pcap_setnonblock(pd, nonblock, NULL);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
/* Nonblocking pcap_next didn't get anything. */
|
||||
if (pcap_status == PCAP_ERROR) {
|
||||
// TODO: Gracefully end the scan.
|
||||
// For now, consider a pcap read error to be fatal.
|
||||
fatal("Error from pcap_next_ex: %s\n", pcap_geterr(pd));
|
||||
}
|
||||
|
||||
if (pcap_status == 0 || p == NULL) {
|
||||
/* Nonblocking pcap_next_ex didn't get anything. */
|
||||
if (pcap_select(pd, to_usec) == 0)
|
||||
timedout = 1;
|
||||
else
|
||||
p = (char *) pcap_next(pd, &head);
|
||||
pcap_status = pcap_next_ex(pd, &head, &p);
|
||||
}
|
||||
|
||||
if (p) {
|
||||
if (head.caplen <= offset) {
|
||||
if (pcap_status == PCAP_ERROR) {
|
||||
// TODO: Gracefully end the scan.
|
||||
fatal("Error from pcap_next_ex: %s\n", pcap_geterr(pd));
|
||||
}
|
||||
|
||||
if (pcap_status == 1 && p) {
|
||||
if (head->caplen <= offset) {
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1709,7 +1726,7 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
}
|
||||
p += offset;
|
||||
}
|
||||
if (!p) {
|
||||
else {
|
||||
/* Should we timeout? */
|
||||
if (to_usec == 0) {
|
||||
timedout = 1;
|
||||
@@ -1726,7 +1743,7 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
*len = head.caplen - offset;
|
||||
*len = head->caplen - offset;
|
||||
if (*len > alignedbufsz) {
|
||||
alignedbuf = (char *) safe_realloc(alignedbuf, *len);
|
||||
alignedbufsz = *len;
|
||||
@@ -1752,9 +1769,9 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
gettimeofday(&tv_end, NULL);
|
||||
*rcvdtime = tv_end;
|
||||
#else
|
||||
rcvdtime->tv_sec = head.ts.tv_sec;
|
||||
rcvdtime->tv_usec = head.ts.tv_usec;
|
||||
assert(head.ts.tv_sec);
|
||||
rcvdtime->tv_sec = head->ts.tv_sec;
|
||||
rcvdtime->tv_usec = head->ts.tv_usec;
|
||||
assert(head->ts.tv_sec);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user