mirror of
https://github.com/nmap/nmap.git
synced 2025-12-24 00:19:01 +00:00
Added ND ping for local IPv6 nets, merging from /nmap-exp/weilin/nmap-nd.
This commit is contained in:
80
tcpip.cc
80
tcpip.cc
@@ -1093,11 +1093,9 @@ u8 *build_icmpv6_raw(const struct in6_addr *source,
|
||||
packet, icmplen, packetlen);
|
||||
|
||||
free(packet);
|
||||
|
||||
return ipv6;
|
||||
}
|
||||
|
||||
|
||||
/* Builds an IGMP packet (including an IP header) by packing the fields
|
||||
with the given information. It allocates a new buffer to store the
|
||||
packet contents, and then returns that buffer. The packet is not
|
||||
@@ -1689,9 +1687,87 @@ char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
return alignedbuf;
|
||||
}
|
||||
|
||||
/* Attempts to read one IPv6 Neighbor Solicitation reply packet from the pcap
|
||||
descriptor pd. If it receives one, fills in sendermac (must pass
|
||||
in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
|
||||
and returns 1. If it times out and reads no Neighbor Advertisement, returns
|
||||
0. to_usec is the timeout period in microseconds. Use 0 to avoid
|
||||
blocking to the extent possible. Returns -1 or exits if there is
|
||||
an error. The last parameter is a pointer to a callback function
|
||||
that can be used for packet tracing. This is intended to be used
|
||||
by Nmap only. Any other calling this should pass NULL instead. */
|
||||
int read_na_pcap(pcap_t *pd, u8 *sendermac, struct sockaddr_in6 *senderIP, long to_usec,
|
||||
struct timeval *rcvdtime, bool *has_mac) {
|
||||
struct ip *ip_tmp;
|
||||
struct icmpv6_hdr *icmp6_header;
|
||||
struct icmpv6_msg_nd *na;
|
||||
struct timeval tv_start, tv_end;
|
||||
const void *data = NULL;
|
||||
unsigned int datalen;
|
||||
static int warning = 0;
|
||||
int timedout = 0;
|
||||
struct abstract_ip_hdr hdr;
|
||||
struct link_header linknfo;
|
||||
|
||||
|
||||
if (to_usec < 0) {
|
||||
if (!warning) {
|
||||
warning = 1;
|
||||
error("WARNING: Negative timeout value (%lu) passed to %s() -- using 0", to_usec, __func__);
|
||||
}
|
||||
to_usec = 0;
|
||||
}
|
||||
|
||||
if (to_usec > 0) {
|
||||
gettimeofday(&tv_start, NULL);
|
||||
}
|
||||
|
||||
do {
|
||||
ip_tmp = (struct ip *) readip_pcap(pd, &datalen, to_usec, rcvdtime,
|
||||
&linknfo, true);
|
||||
if(ip_tmp){ //Check Neighbor Advertisement Packet.
|
||||
/* OK, we got a packet. Most packet validity tests are taken care
|
||||
* of in readip_pcap, so this is simple
|
||||
*/
|
||||
data = ip_get_data(ip_tmp, &datalen, &hdr);
|
||||
if (data == NULL)
|
||||
continue;
|
||||
if (hdr.proto == IPPROTO_ICMPV6){
|
||||
icmp6_header = (struct icmpv6_hdr *)data;
|
||||
na = (struct icmpv6_msg_nd *) ((unsigned char*)data + ICMPV6_HDR_LEN);
|
||||
if (icmp6_header->icmpv6_type == ICMPV6_NEIGHBOR_ADVERTISEMENT &&
|
||||
icmp6_header->icmpv6_code == 0){
|
||||
//Set target IPv6 address
|
||||
senderIP->sin6_family = AF_INET6;
|
||||
memcpy(&senderIP->sin6_addr.s6_addr, &na->icmpv6_target, 16);
|
||||
//Set MAC
|
||||
if (datalen == ICMPV6_HDR_LEN + sizeof(struct icmpv6_msg_nd)){
|
||||
if (na->icmpv6_option_type == 2 && na->icmpv6_option_length == 1){
|
||||
*has_mac = true;
|
||||
memcpy(sendermac, &na->icmpv6_mac, 6);
|
||||
}
|
||||
} else{
|
||||
*has_mac = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Should we timeout? */
|
||||
if (to_usec == 0) {
|
||||
timedout = 1;
|
||||
} else if (to_usec > 0) {
|
||||
gettimeofday(&tv_end, NULL);
|
||||
if (TIMEVAL_SUBTRACT(tv_end, tv_start) >= to_usec) {
|
||||
timedout = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!timedout and !ip_tmp);
|
||||
|
||||
if (timedout)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Returns whether the packet receive time value obtained from libpcap
|
||||
// (and thus by readip_pcap()) should be considered valid. When
|
||||
|
||||
Reference in New Issue
Block a user