1
0
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:
weilin
2011-07-19 02:31:54 +00:00
parent 737035118a
commit 1dcf652410
16 changed files with 707 additions and 33 deletions

View File

@@ -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