mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 12:41: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
|
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
|
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
|
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
|
platforms, we must do a non-blocking read from the fd before doing a select
|
||||||
on the fd.
|
on the fd.
|
||||||
|
|
||||||
@@ -4172,7 +4172,7 @@ int datalink_offset(int datalink)
|
|||||||
the function returns 0 and the output parameters are undefined. */
|
the function returns 0 and the output parameters are undefined. */
|
||||||
static int read_reply_pcap(pcap_t *pd, long to_usec,
|
static int read_reply_pcap(pcap_t *pd, long to_usec,
|
||||||
bool (*accept_callback)(const unsigned char *, const struct pcap_pkthdr *, int, size_t),
|
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)
|
int *datalink, size_t *offset)
|
||||||
{
|
{
|
||||||
static int warning = 0;
|
static int warning = 0;
|
||||||
@@ -4207,6 +4207,7 @@ static int read_reply_pcap(pcap_t *pd, long to_usec,
|
|||||||
do {
|
do {
|
||||||
|
|
||||||
*p = NULL;
|
*p = NULL;
|
||||||
|
int pcap_status = 0;
|
||||||
/* It may be that protecting this with !pcap_selectable_fd_one_to_one is not
|
/* 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
|
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. */
|
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);
|
assert(nonblock == 0);
|
||||||
rc = pcap_setnonblock(pd, 1, NULL);
|
rc = pcap_setnonblock(pd, 1, NULL);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
*p = (u8 *) pcap_next(pd, head);
|
pcap_status = pcap_next_ex(pd, head, p);
|
||||||
rc = pcap_setnonblock(pd, nonblock, NULL);
|
rc = pcap_setnonblock(pd, nonblock, NULL);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == NULL) {
|
if (pcap_status == PCAP_ERROR) {
|
||||||
/* Nonblocking pcap_next didn't get anything. */
|
// 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)
|
if (pcap_select(pd, to_usec) == 0)
|
||||||
timedout = 1;
|
timedout = 1;
|
||||||
else
|
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;
|
break;
|
||||||
} else if (*p == NULL) {
|
} else if (pcap_status == 0 || *p == NULL) {
|
||||||
/* Should we timeout? */
|
/* Should we timeout? */
|
||||||
if (to_usec == 0) {
|
if (to_usec == 0) {
|
||||||
timedout = 1;
|
timedout = 1;
|
||||||
@@ -4264,9 +4275,9 @@ static int read_reply_pcap(pcap_t *pd, long to_usec,
|
|||||||
gettimeofday(&tv_end, NULL);
|
gettimeofday(&tv_end, NULL);
|
||||||
*rcvdtime = tv_end;
|
*rcvdtime = tv_end;
|
||||||
#else
|
#else
|
||||||
rcvdtime->tv_sec = head->ts.tv_sec;
|
rcvdtime->tv_sec = (*head)->ts.tv_sec;
|
||||||
rcvdtime->tv_usec = head->ts.tv_usec;
|
rcvdtime->tv_usec = (*head)->ts.tv_usec;
|
||||||
assert(head->ts.tv_sec);
|
assert((*head)->ts.tv_sec);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4308,8 +4319,8 @@ int read_arp_reply_pcap(pcap_t *pd, u8 *sendermac,
|
|||||||
struct in_addr *senderIP, long to_usec,
|
struct in_addr *senderIP, long to_usec,
|
||||||
struct timeval *rcvdtime,
|
struct timeval *rcvdtime,
|
||||||
void (*trace_callback)(int, const u8 *, u32, struct timeval *)) {
|
void (*trace_callback)(int, const u8 *, u32, struct timeval *)) {
|
||||||
unsigned char *p;
|
const unsigned char *p;
|
||||||
struct pcap_pkthdr head;
|
struct pcap_pkthdr *head;
|
||||||
int datalink;
|
int datalink;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -4360,8 +4371,8 @@ int read_ns_reply_pcap(pcap_t *pd, u8 *sendermac,
|
|||||||
struct sockaddr_in6 *senderIP, long to_usec,
|
struct sockaddr_in6 *senderIP, long to_usec,
|
||||||
struct timeval *rcvdtime,
|
struct timeval *rcvdtime,
|
||||||
void (*trace_callback)(int, const u8 *, u32, struct timeval *)) {
|
void (*trace_callback)(int, const u8 *, u32, struct timeval *)) {
|
||||||
unsigned char *p;
|
const unsigned char *p;
|
||||||
struct pcap_pkthdr head;
|
struct pcap_pkthdr *head;
|
||||||
int datalink;
|
int datalink;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
int rc;
|
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,
|
char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||||
struct timeval *rcvdtime, struct link_header *linknfo, bool validate) {
|
struct timeval *rcvdtime, struct link_header *linknfo, bool validate) {
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
struct pcap_pkthdr head;
|
struct pcap_pkthdr *head;
|
||||||
char *p;
|
const unsigned char *p;
|
||||||
|
int pcap_status = 0;
|
||||||
int datalink;
|
int datalink;
|
||||||
int timedout = 0;
|
int timedout = 0;
|
||||||
struct timeval tv_start, tv_end;
|
struct timeval tv_start, tv_end;
|
||||||
@@ -1651,18 +1652,22 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
p = (char *) pcap_next(pd, &head);
|
pcap_status = pcap_next_ex(pd, &head, &p);
|
||||||
if (head.caplen == 0) {
|
if (pcap_status == 0) {
|
||||||
/* Lets sleep a brief time and try again to increase the chance of seeing
|
/* Lets sleep a brief time and try again to increase the chance of seeing
|
||||||
a real packet ... */
|
a real packet ... */
|
||||||
usleep(500000);
|
usleep(500000);
|
||||||
p = (char *) pcap_next(pd, &head);
|
pcap_status = pcap_next_ex(pd, &head, &p);
|
||||||
}
|
}
|
||||||
if (head.caplen > 100000) {
|
if (pcap_status != 1 || !head) {
|
||||||
fatal("FATAL: %s: bogus caplen from libpcap (%d) on interface type %d", __func__, head.caplen, datalink);
|
// No packet captured
|
||||||
|
fatal("FATAL: Unknown datalink type (%d).", datalink);
|
||||||
}
|
}
|
||||||
error("FATAL: Unknown datalink type (%d). Caplen: %d; Packet:", datalink, head.caplen);
|
if (head->caplen > 100000 || !p) {
|
||||||
nmap_hexdump((unsigned char *) p, head.caplen);
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1673,6 +1678,7 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
|||||||
do {
|
do {
|
||||||
|
|
||||||
p = NULL;
|
p = NULL;
|
||||||
|
pcap_status = 0;
|
||||||
/* It may be that protecting this with !pcap_selectable_fd_one_to_one is not
|
/* 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
|
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. */
|
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);
|
assert(nonblock == 0);
|
||||||
rc = pcap_setnonblock(pd, 1, NULL);
|
rc = pcap_setnonblock(pd, 1, NULL);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
p = (char *) pcap_next(pd, &head);
|
pcap_status = pcap_next_ex(pd, &head, &p);
|
||||||
rc = pcap_setnonblock(pd, nonblock, NULL);
|
rc = pcap_setnonblock(pd, nonblock, NULL);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p == NULL) {
|
if (pcap_status == PCAP_ERROR) {
|
||||||
/* Nonblocking pcap_next didn't get anything. */
|
// 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)
|
if (pcap_select(pd, to_usec) == 0)
|
||||||
timedout = 1;
|
timedout = 1;
|
||||||
else
|
else
|
||||||
p = (char *) pcap_next(pd, &head);
|
pcap_status = pcap_next_ex(pd, &head, &p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p) {
|
if (pcap_status == PCAP_ERROR) {
|
||||||
if (head.caplen <= offset) {
|
// 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;
|
*len = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1709,7 +1726,7 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
|||||||
}
|
}
|
||||||
p += offset;
|
p += offset;
|
||||||
}
|
}
|
||||||
if (!p) {
|
else {
|
||||||
/* Should we timeout? */
|
/* Should we timeout? */
|
||||||
if (to_usec == 0) {
|
if (to_usec == 0) {
|
||||||
timedout = 1;
|
timedout = 1;
|
||||||
@@ -1726,7 +1743,7 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
|||||||
*len = 0;
|
*len = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*len = head.caplen - offset;
|
*len = head->caplen - offset;
|
||||||
if (*len > alignedbufsz) {
|
if (*len > alignedbufsz) {
|
||||||
alignedbuf = (char *) safe_realloc(alignedbuf, *len);
|
alignedbuf = (char *) safe_realloc(alignedbuf, *len);
|
||||||
alignedbufsz = *len;
|
alignedbufsz = *len;
|
||||||
@@ -1752,9 +1769,9 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
|||||||
gettimeofday(&tv_end, NULL);
|
gettimeofday(&tv_end, NULL);
|
||||||
*rcvdtime = tv_end;
|
*rcvdtime = tv_end;
|
||||||
#else
|
#else
|
||||||
rcvdtime->tv_sec = head.ts.tv_sec;
|
rcvdtime->tv_sec = head->ts.tv_sec;
|
||||||
rcvdtime->tv_usec = head.ts.tv_usec;
|
rcvdtime->tv_usec = head->ts.tv_usec;
|
||||||
assert(head.ts.tv_sec);
|
assert(head->ts.tv_sec);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user