1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +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

@@ -306,6 +306,14 @@ const struct in_addr *Target::v4sourceip() const {
return NULL; return NULL;
} }
// Returns IPv6 host address or NULL if unavailable.
const struct in6_addr *Target::v6sourceip() const {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &sourcesock;
if (sin6->sin6_family == AF_INET6) {
return &(sin6->sin6_addr);
}
return NULL;
}
/* You can set to NULL to erase a name or if it failed to resolve -- or /* You can set to NULL to erase a name or if it failed to resolve -- or
just don't call this if it fails to resolve */ just don't call this if it fails to resolve */

View File

@@ -182,6 +182,7 @@ class Target {
void setSourceSockAddr(const struct sockaddr_storage *ss, size_t ss_len); void setSourceSockAddr(const struct sockaddr_storage *ss, size_t ss_len);
struct in_addr v4source() const; struct in_addr v4source() const;
const struct in_addr *v4sourceip() const; const struct in_addr *v4sourceip() const;
const struct in6_addr *v6sourceip() const;
/* The IPv4 or IPv6 literal string for the target host */ /* The IPv4 or IPv6 literal string for the target host */
const char *targetipstr() const { return targetipstring; } const char *targetipstr() const { return targetipstring; }
/* Give the name from the last setHostName() call, which should be /* Give the name from the last setHostName() call, which should be

View File

@@ -244,6 +244,6 @@ struct scan_lists {
int prot_count; int prot_count;
}; };
typedef enum { STYPE_UNKNOWN, HOST_DISCOVERY, ACK_SCAN, SYN_SCAN, FIN_SCAN, XMAS_SCAN, UDP_SCAN, CONNECT_SCAN, NULL_SCAN, WINDOW_SCAN, SCTP_INIT_SCAN, SCTP_COOKIE_ECHO_SCAN, RPC_SCAN, MAIMON_SCAN, IPPROT_SCAN, PING_SCAN, PING_SCAN_ARP, IDLE_SCAN, BOUNCE_SCAN, SERVICE_SCAN, OS_SCAN, SCRIPT_PRE_SCAN, SCRIPT_SCAN, SCRIPT_POST_SCAN, TRACEROUTE}stype; typedef enum { STYPE_UNKNOWN, HOST_DISCOVERY, ACK_SCAN, SYN_SCAN, FIN_SCAN, XMAS_SCAN, UDP_SCAN, CONNECT_SCAN, NULL_SCAN, WINDOW_SCAN, SCTP_INIT_SCAN, SCTP_COOKIE_ECHO_SCAN, RPC_SCAN, MAIMON_SCAN, IPPROT_SCAN, PING_SCAN, PING_SCAN_ARP, IDLE_SCAN, BOUNCE_SCAN, SERVICE_SCAN, OS_SCAN, SCRIPT_PRE_SCAN, SCRIPT_SCAN, SCRIPT_POST_SCAN, TRACEROUTE, PING_SCAN_ND }stype;
#endif /*GLOBAL_STRUCTURES_H */ #endif /*GLOBAL_STRUCTURES_H */

View File

@@ -103,7 +103,7 @@ union icmpv6_msg {
memmove(echo_pack_p->icmpv6_data, data, len); \ memmove(echo_pack_p->icmpv6_data, data, len); \
} while (0) } while (0)
#define icmpv6_pack_hdr_ns(hdr, targetip, srcmac) do { \ #define icmpv6_pack_hdr_ns_mac(hdr, targetip, srcmac) do { \
struct icmpv6_msg_nd *nd_pack_p = (struct icmpv6_msg_nd *) \ struct icmpv6_msg_nd *nd_pack_p = (struct icmpv6_msg_nd *) \
((uint8_t *)(hdr) + ICMPV6_HDR_LEN); \ ((uint8_t *)(hdr) + ICMPV6_HDR_LEN); \
icmpv6_pack_hdr(hdr, ICMPV6_NEIGHBOR_SOLICITATION, 0); \ icmpv6_pack_hdr(hdr, ICMPV6_NEIGHBOR_SOLICITATION, 0); \

View File

@@ -1567,25 +1567,31 @@ struct sys_route *getsysroutes(int *howmany, char *errstr, size_t errstrlen) {
* localhost. (eg: the address is something like 127.x.x.x, the address * localhost. (eg: the address is something like 127.x.x.x, the address
* matches one of the local network interfaces' address, etc). * matches one of the local network interfaces' address, etc).
* Returns 1 if the address is thought to be localhost and 0 otherwise */ * Returns 1 if the address is thought to be localhost and 0 otherwise */
int islocalhost(const struct in_addr *const addr) { int islocalhost(const struct sockaddr_storage *const ss) {
char dev[128]; char dev[128];
struct sockaddr_storage ss; struct sockaddr_in *sin = NULL;
struct sockaddr_in *sin; struct sockaddr_in6 *sin6 = NULL;
/* If it is 0.0.0.0 or starts with 127 then it is if (ss->ss_family == AF_INET){
probably localhost */ sin = (struct sockaddr_in *) ss;
if ((addr->s_addr & htonl(0xFF000000)) == htonl(0x7F000000)) /* If it is 0.0.0.0 or starts with 127 then it is probably localhost. */
return 1; if ((sin->sin_addr.s_addr & htonl(0xFF000000)) == htonl(0x7F000000))
return 1;
if (!addr->s_addr) if (!(sin->sin_addr.s_addr))
return 1; return 1;
} else {
sin6 = (struct sockaddr_in6 *) ss;
/* If it is ::0 or ::1 then it is probably localhost. */
if (memcmp(&(sin6->sin6_addr), IP6_ADDR_UNSPEC, IP6_ADDR_LEN) == 0)
return 1;
if (memcmp(&(sin6->sin6_addr), IP6_ADDR_LOOPBACK, IP6_ADDR_LEN) == 0)
return 1;
}
/* If it is the same addy as a local interface, then it is /* If it is the same addy as a local interface, then it is
probably localhost */ probably localhost */
sin = (struct sockaddr_in *) &ss; if (ipaddr2devname(dev, ss) != -1)
sin->sin_family = AF_INET;
sin->sin_addr = *addr;
if (ipaddr2devname(dev, &ss) != -1)
return 1; return 1;
/* OK, so to a first approximation, this addy is probably not /* OK, so to a first approximation, this addy is probably not
@@ -4073,7 +4079,7 @@ bool doND(const char *dev, const u8 *srcmac,
netutil_fatal("%s: failed to open device %s", __func__, dev); netutil_fatal("%s: failed to open device %s", __func__, dev);
eth_pack_hdr(frame, *ns_dst_mac, *srcmac, ETH_TYPE_IPV6); eth_pack_hdr(frame, *ns_dst_mac, *srcmac, ETH_TYPE_IPV6);
ip6_pack_hdr(frame + ETH_HDR_LEN, 0, 0, 32, 0x3a, 255, *src_sin6->sin6_addr.s6_addr, *ns_dst_ip6.sin6_addr.s6_addr); ip6_pack_hdr(frame + ETH_HDR_LEN, 0, 0, 32, 0x3a, 255, *src_sin6->sin6_addr.s6_addr, *ns_dst_ip6.sin6_addr.s6_addr);
icmpv6_pack_hdr_ns(frame + ETH_HDR_LEN + IP6_HDR_LEN, target_sin6->sin6_addr.s6_addr, *srcmac); icmpv6_pack_hdr_ns_mac(frame + ETH_HDR_LEN + IP6_HDR_LEN, target_sin6->sin6_addr.s6_addr, *srcmac);
ip6_checksum(frame + ETH_HDR_LEN, IP6_HDR_LEN + ICMPV6_HDR_LEN + 4 + 16 + 8); ip6_checksum(frame + ETH_HDR_LEN, IP6_HDR_LEN + ICMPV6_HDR_LEN + 4 + 16 + 8);
gettimeofday(&start, NULL); gettimeofday(&start, NULL);

View File

@@ -376,7 +376,7 @@ struct sys_route *getsysroutes(int *howmany, char *errstr, size_t errstrlen);
* localhost. (eg: the address is something like 127.x.x.x, the address * localhost. (eg: the address is something like 127.x.x.x, the address
* matches one of the local network interfaces' address, etc). * matches one of the local network interfaces' address, etc).
* Returns 1 if the address is thought to be localhost and 0 otherwise */ * Returns 1 if the address is thought to be localhost and 0 otherwise */
int islocalhost(const struct in_addr *const addr); int islocalhost(const struct sockaddr_storage *const ss);
/* Determines whether the supplied address corresponds to a private, /* Determines whether the supplied address corresponds to a private,
* non-Internet-routable address. See RFC1918 for details. * non-Internet-routable address. See RFC1918 for details.
@@ -514,6 +514,10 @@ 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 (*traceArp_callback)(int, const u8 *, u32 , struct timeval *)); void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *));
int read_ns_reply_pcap(pcap_t *pd, u8 *sendermac,
struct sockaddr_in6 *senderIP, long to_usec,
struct timeval *rcvdtime,
void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *));
/* Read a single host specification from a file, as for -iL and --excludefile. /* Read a single host specification from a file, as for -iL and --excludefile.
It returns the length of the string read; an overflow is indicated when the It returns the length of the string read; an overflow is indicated when the

View File

@@ -2627,6 +2627,7 @@ const char *scantype2str(stype scantype) {
case IPPROT_SCAN: return "IPProto Scan"; break; case IPPROT_SCAN: return "IPProto Scan"; break;
case PING_SCAN: return "Ping Scan"; break; case PING_SCAN: return "Ping Scan"; break;
case PING_SCAN_ARP: return "ARP Ping Scan"; break; case PING_SCAN_ARP: return "ARP Ping Scan"; break;
case PING_SCAN_ND: return "ND Ping Scan"; break;
case IDLE_SCAN: return "Idle Scan"; break; case IDLE_SCAN: return "Idle Scan"; break;
case BOUNCE_SCAN: return "Bounce Scan"; break; case BOUNCE_SCAN: return "Bounce Scan"; break;
case SERVICE_SCAN: return "Service Scan"; break; case SERVICE_SCAN: return "Service Scan"; break;

View File

@@ -120,6 +120,83 @@ IPPROTO_COMP = 108 -- Compression Header protocol
IPPROTO_SCTP = 132 -- Stream Control Transport Protocol IPPROTO_SCTP = 132 -- Stream Control Transport Protocol
IPPROTO_UDPLITE = 136 -- UDP-Lite (RFC 3828) IPPROTO_UDPLITE = 136 -- UDP-Lite (RFC 3828)
IPPROTO_ICMPV6 = 58
IPV6_HOPBYHOP_OPTION = 0
IPV6_DESTINATION_OPTION = 60
IP_PROTO_ICMPV6 = 58
ICMP6_ECHO_REQUEST = 128
ICMP6_ECHO_REPLY = 129
MLD_LISTENER_QUERY = 130
MLD_LISTENER_REPORT = 131
MLD_LISTENER_REDUCTION = 132
ND_ROUTER_SOLICIT = 133
ND_ROUTER_ADVERT = 134
ND_NEIGHBOR_SOLICIT = 135
ND_NEIGHBOR_ADVERT = 136
ND_REDIRECT = 137
ND_OPT_SOURCE_LINKADDR = 1
ND_OPT_TARGET_LINKADDR = 2
ND_OPT_PREFIX_INFORMATION = 3
ND_OPT_REDIRECTED_HEADER = 4
ND_OPT_MTU = 5
ND_OPT_RTR_ADV_INTERVAL = 7
ND_OPT_HOME_AGENT_INFO = 8
----------------------------------------------------------------------------------------------------------------
-- Frame is a class
Frame = {}
function Frame:new(frame, force_continue)
local packet = nil
local packet_len = 0
if frame and #frame > 14 then
packet = string.sub(frame, 15, -1)
packet_len = #frame - 14
end
local o = Packet:new(packet, packet_len, force_continue)
o.build_ether_frame = self.build_ether_frame
o.ether_parse = self.ether_parse
o.frame_buf = frame
o:ether_parse()
return o
end
--- Build an Ethernet frame.
-- @param mac_dst six-byte string of the destination MAC address.
-- @param mac_src six-byte string of the source MAC address.
-- @param packet string of the payload.
-- @return frame string of the Ether frame.
function Frame:build_ether_frame(mac_dst, mac_src, packet)
self.mac_dst = mac_dst or self.mac_dst
self.mac_src = mac_src or self.mac_src
self.buf = packet or self.buf
local l3_type
if self.ip_v == 4 then
l3_type = string.char(0x08, 0x00)
elseif self.ip_v == 6 then
l3_type = string.char(0x86, 0xdd)
else
return nil, "Unknown packet."
end
self.frame_buf = self.mac_dst..self.mac_src..l3_type..self.buf
end
--- Parse an Ethernet frame.
-- @param frame string of the Ether frame.
-- @return mac_dst six-byte string of the destination MAC address.
-- @return mac_src six-byte string of the source MAC address.
-- @return packet string of the payload.
function Frame:ether_parse()
if not self.frame_buf then
return false
end
if #self.frame_buf < 14 then -- too short
return false
end
self.mac_dst = string.sub(self.frame_buf, 1, 6)
self.mac_src = string.sub(self.frame_buf, 7, 12)
end
---------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------
-- Packet is a class -- Packet is a class
@@ -136,11 +213,27 @@ Packet = {}
-- @return A new Packet. -- @return A new Packet.
function Packet:new(packet, packet_len, force_continue) function Packet:new(packet, packet_len, force_continue)
local o = setmetatable({}, {__index = Packet}) local o = setmetatable({}, {__index = Packet})
if not packet then
return o
end
o.buf = packet o.buf = packet
o.packet_len = packet_len o.packet_len = packet_len
if not o:ip_parse(force_continue) then o.ip_v = bit.rshift(string.byte(o.buf), 4)
if o.ip_v == 4 and not o:ip_parse(force_continue) then
return nil
elseif o.ip_v == 6 and not o:ip6_parse(force_continue) then
return nil return nil
end end
if o.ip_v == 6 then
while o.ip6_nhdr ~= IPPROTO_TCP and o.ip6_nhdr ~= IPPROTO_UDP and o.ip6_nhdr ~= IPPROTO_ICMPV6 do
if not o:ipv6_ext_header_parse(force_continue) then
return nil
end
end
o.ip_p = o.ip6_nhdr
end
if o.ip_p == IPPROTO_TCP then if o.ip_p == IPPROTO_TCP then
if not o:tcp_parse(force_continue) then if not o:tcp_parse(force_continue) then
stdnse.print_debug("Error while parsing TCP packet\n") stdnse.print_debug("Error while parsing TCP packet\n")
@@ -153,9 +246,151 @@ function Packet:new(packet, packet_len, force_continue)
if not o:icmp_parse(force_continue) then if not o:icmp_parse(force_continue) then
stdnse.print_debug("Error while parsing ICMP packet\n") stdnse.print_debug("Error while parsing ICMP packet\n")
end end
elseif o.ip_p == IPPROTO_ICMPV6 then
if not o:icmpv6_parse(force_continue) then
stdnse.print_debug("Error while parsing ICMPv6 packet\n")
end
end end
return o return o
end end
--- Build an IPv6 packet.
-- @param src 16-byte string of the source IPv6 address.
-- @param dsr 16-byte string of the destination IPv6 address.
-- @param nx_hdr integer that represents next header.
-- @param h_limit integer that represents hop limit.
-- @param t_class integer that represents traffic class.
-- @param f_label integer that represents flow label.
function Packet:build_ipv6_packet(src, dst, nx_hdr, payload, h_limit, t_class, f_label)
self.ip_v = 6
self.ip6_src = src or self.ip6_src
self.ip6_dst = dst or self.ip6_dst
self.ip6_nhdr = nx_hdr or self.ip6_nhdr
self.l4_packet = payload or self.l4_packet
self.ip6_tc = t_class or self.ip6_tc or 1
self.ip6_fl = f_label or self.ip6_fl or 1
self.ip6_hlimit = h_limit or self.ip6_hlimit or 255
local ver_tc_fl = bit.lshift(bit.band(self.ip_v, 0xF), 28) +
bit.lshift(bit.band(self.ip6_tc, 0xFF), 20) +
bit.band(self.ip6_fl, 0xFFFFF)
self.buf =
set_u32("....",0,ver_tc_fl) ..
set_u16("..",0,#(self.exheader or "")+#(self.l4_packet or "")) ..--string.char(0x00,0x10) .. --payload length
string.char(self.ip6_nxt_hdr) .. --next header
string.char(self.ip6_hlimit) .. --hop limit
self.ip6_src .. --Source
self.ip6_dst ..--dest
(self.exheader or "")..
(self.l4_packet or "")
end
--- Build an IPv6 invalid extension header.
-- @param exheader integer that represents extension header's type
function Packet:build_invalid_extension_header(exheader_type)
local ex_invalid_opt = string.char(0x80,0x01,0xfe,0x18,0xfe,0x18,0xfe,0x18,0x0,0x0,0x0,0x0,0x0,0x0)
local ext_header =
string.char(self.ip6_nxt_hdr) .. --next header
string.char(#ex_invalid_opt/16) .. --length (16bytes)
ex_invalid_opt
self.exheader = ext_header..(self.exheader or "")
self.ip6_nxt_hdr = exheader_type
end
--- Count IPv6 checksum.
-- @return the checksum.
function Packet:count_ipv6_pseudoheader_cksum()
local pseudoheader = self.ip6_src .. self.ip6_dst .. set_u16("..",0,#self.l4_packet) .. string.char(0x0,0x0,0x0) .. string.char(self.ip6_nxt_hdr)
local ck_content = pseudoheader .. self.l4_packet
return in_cksum(ck_content)
end
--- Set ICMPv6 checksum.
function Packet:set_icmp6_cksum(check_sum)
self.l4_packet = set_u16(self.l4_packet, 2, check_sum)
end
--- Build an ICMPv6 header.
-- @param icmpv6_type integer that represent ICMPv6 type.
-- @param icmpv6_code integer that represent ICMPv6 code.
-- @param icmpv6_payload string of the payload
-- @param ip6_src 16-byte string of the source IPv6 address.
-- @param ip6_dst 16-byte string of the destination IPv6 address.
function Packet:build_icmpv6_header(icmpv6_type, icmpv6_code, icmpv6_payload, ip6_src, ip6_dst)
self.ip6_nxt_hdr = IPPROTO_ICMPV6
self.icmpv6_type = icmpv6_type or self.icmpv6_type
self.icmpv6_code = icmpv6_code or self.icmpv6_code
self.icmpv6_payload = icmpv6_payload or self.icmpv6_payload
self.ip6_src = ip6_src or self.ip6_src
self.ip6_dst = ip6_dst or self.ip6_dst
self.l4_packet =
string.char(self.icmpv6_type,self.icmpv6_code) ..
string.char(0x00,0x00) .. --checksum
(self.icmpv6_payload or "")
local check_sum = self:count_ipv6_pseudoheader_cksum()
self:set_icmp6_cksum(check_sum)
end
--- Build an ICMPv6 Echo Request frame.
-- @param mac_src six-byte string of source MAC address.
-- @param mac_dst sis-byte string of destination MAC address.
-- @param ip6_src 16-byte string of source IPv6 address.
-- @param ip6_dst 16-byte string of destinatiion IPv6 address.
-- @param id integer that represents Echo ID.
-- @param sequence integer that represents Echo sequence.
-- @param data string of Echo data.
-- @param tc integer that represents traffic class of IPv6 packet.
-- @param fl integer that represents flow label of IPv6 packet.
-- @param hop-limit integer that represents hop limit of IPv6 packet.
function Packet:build_icmpv6_echo_request(id, sequence, data, mac_src, mac_dst, ip6_src, ip6_dst, tc, fl, hop_limit)
self.mac_src = mac_src or self.mac_src
self.mac_dst = mac_dst or self.mac_dst
self.ip6_src = ip6_src or self.ip6_src
self.ip6_dst = ip6_dst or self.ip6_dst
self.traffic_class = tc or 1
self.flow_label = fl or 1
self.ip6_hlimit = hop_limit or 255
self.icmpv6_type = ICMP6_ECHO_REQUEST
self.icmpv6_code = 0
self.echo_id = id or self.echo_id or 0xdead
self.echo_seq = sequence or self.echo_seq or 0xbeef
self.echo_data = data or self.echo_data or ""
self.icmpv6_payload = set_u16("..",0,self.echo_id) .. set_u16("..",0,self.echo_seq) .. self.echo_data
end
--- Set an ICMPv6 option message.
function Packet:set_icmpv6_option(opt_type,msg)
return string.char(opt_type, (#msg+2)/8) .. msg
end
--- Build an Router Advertisement frame.
-- @param mac_src six-byte string of the source MAC address.
-- @param prefix 16-byte string of IPv6 address.
-- @param prefix_len integer that represents the length of the prefix.
-- @param valid_time integer that represents the valid time of the prefix.
-- @param preferred_time integer that represents the preferred time of the prefix.
function Packet:build_router_advert(mac_src,prefix,prefix_len,valid_time,preferred_time)
self.ip6_src = mac_to_lladdr(mac_src)
self.ip6_dst = ipv6tobin("ff02::1")
self.mac_src = mac_src
self.mac_dst = mactobin("33:33:00:00:00:01")
local ra_msg = string.char(0x0, --cur hop limit
0x08, --flags
0x00,0x00, --router lifetime
0x00,0x00,0x00,0x00, --reachable time
0x00,0x00,0x00,0x00) --retrans timer
local prefix_option_msg = string.char(prefix_len,
0xc0) .. --flags: Onlink, Auto
packet.set_u32("....",0,valid_time) ..
packet.set_u32("....",0,preferred_time) ..
string.char(0,0,0,0) .. --unknown
prefix
local icmpv6_prefix_option = self:set_icmpv6_option(ND_OPT_PREFIX_INFORMATION,prefix_option_msg)
local icmpv6_src_link_option = self:set_icmpv6_option(ND_OPT_SOURCE_LINKADDR,mac_src)
self.icmpv6_payload = ra_msg .. icmpv6_prefix_option .. icmpv6_src_link_option
self.icmpv6_type = ND_ROUTER_ADVERT
self.icmpv6_code = 0
end
-- Helpers -- Helpers
@@ -171,6 +406,73 @@ function iptobin(str)
end end
return ret return ret
end end
function inet6_pton_simple(str)
local addr_hex = ""
if str==nil then
return addr_hex
end
local unit16
for unit16 in string.gmatch(str, "%x+") do
local h8 = string.sub(unit16,-4,-3)
local l8 = string.sub(unit16,-2,-1)
local unit8
for _,unit8 in pairs({h8,l8}) do
if (unit8 == "") then
addr_hex = addr_hex .. string.char(0x00)
else
addr_hex = addr_hex .. string.char("0x"..unit8)
end
end
end
return addr_hex
end
--- Convert an IPv6 address string (like <code>"fe80:21::1"</code>) to a raw
-- string 16 bytes long.
-- @param str IPv6 address string.
-- @return 16-byte string.
function ipv6tobin(str)
if not str then
return nil
end
local check_str = string.gsub(str,":","f")
if string.match(check_str,"[%X]") then
return nil,"Invalid IPv6 address: unknown character."
end
local i,j
i,j = string.find(str,"::")
if not i then
return inet6_pton_simple(str)
end
local lpart
local rpart
lpart = string.match(str,"([%x:]-)::")
rpart = string.match(str,"::([%x:]+)")
local lpart_hex = inet6_pton_simple(lpart)
local rpart_hex = inet6_pton_simple(rpart)
if (#lpart_hex+#rpart_hex~=16) then
local filler_num = 16 - #lpart_hex - #rpart_hex
local i
for i=1,filler_num do
lpart_hex = lpart_hex .. string.char(0x00)
end
end
return lpart_hex .. rpart_hex
end
--- Convert a MAC address string (like <code>"00:23:ae:5d:3b:10"</code>) to
-- a raw six-byte long.
-- @param str MAC address string.
-- @return Six-byte string.
function mactobin(str)
if not str then
return mactobin("00:00:00:00:00:00")
end
local unit8
local addr_hex = ""
for unit8 in string.gmatch(str,"%x+") do
addr_hex = addr_hex .. string.char("0x"..unit8)
end
return addr_hex
end
--- Convert a four-byte raw string to a dotted-quad IP address string. --- Convert a four-byte raw string to a dotted-quad IP address string.
-- @param raw_ip_addr Four-byte string. -- @param raw_ip_addr Four-byte string.
-- @return IP address string. -- @return IP address string.
@@ -180,6 +482,27 @@ function toip(raw_ip_addr)
end end
return string.format("%i.%i.%i.%i", string.byte(raw_ip_addr,1,4)) return string.format("%i.%i.%i.%i", string.byte(raw_ip_addr,1,4))
end end
--- Convert a 16-byte raw string to an IPv6 address string.
-- @param raw_ipv6_addr 16-byte string.
-- @return IPv6 address string.
function toipv6(raw_ipv6_addr)
if not raw_ipv6_addr then
return "?::?"
end
return string.format("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
string.byte(raw_ipv6_addr,1,16))
end
--- Generate the link-local IPv6 address from the MAC address.
-- @param mac MAC address string.
-- @return Link-local IPv6 address string.
function mac_to_lladdr(mac)
if not mac then
return "?::?"
end
local interfier = string.char(bit.bor(string.byte(mac,1),0x02))..string.sub(mac,2,3)..string.char(0xff,0xfe)..string.sub(mac,4,6)
local ll_prefix = ipv6tobin("fe80::")
return string.sub(ll_prefix,1,8)..interfier
end
--- Get an 8-bit integer at a 0-based byte offset in the packet. --- Get an 8-bit integer at a 0-based byte offset in the packet.
-- @param index Offset. -- @param index Offset.
-- @return An 8-bit integer. -- @return An 8-bit integer.
@@ -269,6 +592,38 @@ function Packet:ip_parse(force_continue)
self.ip_data_offset = self.ip_offset + self.ip_hl*4 self.ip_data_offset = self.ip_offset + self.ip_hl*4
return true return true
end end
--- Parse an IPv6 packet header.
-- @param force_continue Ignored.
-- @return Whether the parsing succeeded.
function Packet:ip6_parse(force_continue)
self.ip6_offset = 0
if #self.buf < 40 then -- too short
return false
end
self.ip_v = bit.rshift(bit.band(self:u8(self.ip6_offset + 0), 0xF0), 4)
if self.ip_v ~= 6 then -- not ipv6
return false
end
self.ip6 = true
self.ip6_tc = bit.rshift(bit.band(self:u16(self.ip6_offset + 0), 0x0FF0), 4)
self.ip6_fl = bit.band(self:u8(self.ip6_offset + 1), 0x0F)*65536 + self:u16(self.ip6_offset + 2)
self.ip6_plen = self:u16(self.ip6_offset + 4)
self.ip6_nhdr = self:u8(self.ip6_offset + 6)
self.ip6_hlimt = self:u8(self.ip6_offset + 7)
self.ip6_src = self:raw(self.ip6_offset + 8, 16)
self.ip6_dst = self:raw(self.ip6_offset + 24, 16)
self.ip6_data_offset = 40
return true
end
--- Pare an IPv6 extension header. Just jump over it at the moment.
-- @param force_continue Ignored.
-- @return Whether the parsing succeeded.
function Packet:ipv6_ext_header_parse(force_continue)
local ext_hdr_len = self.u8(self.ip6_data_offset + 1)
ext_hdr_len = ext_hdr_len*8 + 8
self.ip6_data_offset = self.ip6_data_offset + ext_hdr_len
self.ip6_nhdr = self.u8(self.ip6_data_offset)
end
--- Set the header length field. --- Set the header length field.
function Packet:ip_set_hl(len) function Packet:ip_set_hl(len)
self:set_u8(self.ip_offset + 0, bit.bor(bit.lshift(self.ip_v, 4), bit.band(len, 0x0F))) self:set_u8(self.ip_offset + 0, bit.bor(bit.lshift(self.ip_v, 4), bit.band(len, 0x0F)))
@@ -420,6 +775,25 @@ function Packet:icmp_tostring()
return self:ip_tostring() .. " ICMP(" .. self.icmp_payload:tostring() .. ")" return self:ip_tostring() .. " ICMP(" .. self.icmp_payload:tostring() .. ")"
end end
----------------------------------------------------------------------------------------------------------------
--- Parse an ICMPv6 packet header.
-- @param force_continue Ignored.
-- @return Whether the parsing succeeded.
function Packet:icmpv6_parse(force_continue)
self.icmpv6_offset = self.ip6_data_offset
if #self.buf < self.icmpv6_offset + 8 then -- let's say 8 bytes minimum
return false
end
self.icmpv6 = true
self.icmpv6_type = self:u8(self.icmpv6_offset + 0)
self.icmpv6_code = self:u8(self.icmpv6_offset + 1)
if self.icmpv6_type == ND_NEIGHBOR_SOLICIT then
self.ns_target = self:raw(self.icmpv6_offset + 8, 16)
end
return true
end
---------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------
-- Parse a TCP packet header. -- Parse a TCP packet header.
-- @param force_continue Whether a short packet causes parsing to fail. -- @param force_continue Whether a short packet causes parsing to fail.

View File

@@ -1809,7 +1809,7 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
} }
if (good_tcp_ipid_num >= 3) { if (good_tcp_ipid_num >= 3) {
tcp_ipid_seqclass = get_ipid_sequence(good_tcp_ipid_num, hss->ipid.tcp_ipids, islocalhost(hss->target->v4hostip())); tcp_ipid_seqclass = get_ipid_sequence(good_tcp_ipid_num, hss->ipid.tcp_ipids, islocalhost(hss->target->TargetSockAddr()));
} else { } else {
tcp_ipid_seqclass = IPID_SEQ_UNKNOWN; tcp_ipid_seqclass = IPID_SEQ_UNKNOWN;
} }
@@ -1817,13 +1817,13 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
hss->si.ipid_seqclass = tcp_ipid_seqclass; hss->si.ipid_seqclass = tcp_ipid_seqclass;
if (good_tcp_closed_ipid_num >= 2) { if (good_tcp_closed_ipid_num >= 2) {
tcp_closed_ipid_seqclass = get_ipid_sequence(good_tcp_closed_ipid_num, hss->ipid.tcp_closed_ipids, islocalhost(hss->target->v4hostip())); tcp_closed_ipid_seqclass = get_ipid_sequence(good_tcp_closed_ipid_num, hss->ipid.tcp_closed_ipids, islocalhost(hss->target->TargetSockAddr()));
} else { } else {
tcp_closed_ipid_seqclass = IPID_SEQ_UNKNOWN; tcp_closed_ipid_seqclass = IPID_SEQ_UNKNOWN;
} }
if (good_icmp_ipid_num >= 2) { if (good_icmp_ipid_num >= 2) {
icmp_ipid_seqclass = get_ipid_sequence(good_icmp_ipid_num, hss->ipid.icmp_ipids, islocalhost(hss->target->v4hostip())); icmp_ipid_seqclass = get_ipid_sequence(good_icmp_ipid_num, hss->ipid.icmp_ipids, islocalhost(hss->target->TargetSockAddr()));
} else { } else {
icmp_ipid_seqclass = IPID_SEQ_UNKNOWN; icmp_ipid_seqclass = IPID_SEQ_UNKNOWN;
} }
@@ -3610,7 +3610,7 @@ static void endRound(OsScanInfo *OSI, HostOsScan *HOS, int roundNum) {
hsi->isCompleted = true; hsi->isCompleted = true;
} }
if (islocalhost(hsi->target->v4hostip())) { if (islocalhost(hsi->target->TargetSockAddr())) {
/* scanning localhost */ /* scanning localhost */
distance = 0; distance = 0;
distance_calculation_method = DIST_METHOD_LOCALHOST; distance_calculation_method = DIST_METHOD_LOCALHOST;

View File

@@ -150,6 +150,7 @@ reason_map_type::reason_map_type(){
reason_map[ER_IPIDCHANGE] = reason_string("ipid-change","ipid-changes"); reason_map[ER_IPIDCHANGE] = reason_string("ipid-change","ipid-changes");
reason_map[ER_ARPRESPONSE] = reason_string("arp-response","arp-responses"); reason_map[ER_ARPRESPONSE] = reason_string("arp-response","arp-responses");
reason_map[ER_NDRESPONSE] = reason_string("nd-response","nd-responses");
reason_map[ER_TCPRESPONSE] = reason_string("tcp-response","tcp-responses"); reason_map[ER_TCPRESPONSE] = reason_string("tcp-response","tcp-responses");
reason_map[ER_NORESPONSE] = reason_string("no-response","no-responses"); reason_map[ER_NORESPONSE] = reason_string("no-response","no-responses");

View File

@@ -150,7 +150,7 @@ enum reason_codes {
ER_TIMEEXCEEDED, ER_TIMESTAMPREPLY, ER_TIMEEXCEEDED, ER_TIMESTAMPREPLY,
ER_ADDRESSMASKREPLY, ER_NOIPIDCHANGE, ER_IPIDCHANGE, ER_ADDRESSMASKREPLY, ER_NOIPIDCHANGE, ER_IPIDCHANGE,
ER_ARPRESPONSE, ER_TCPRESPONSE, ER_NORESPONSE, ER_ARPRESPONSE, ER_NDRESPONSE, ER_TCPRESPONSE, ER_NORESPONSE,
ER_INITACK, ER_ABORT, ER_INITACK, ER_ABORT,
ER_LOCALHOST, ER_SCRIPT, ER_UNKNOWN, ER_USER, ER_LOCALHOST, ER_SCRIPT, ER_UNKNOWN, ER_USER,
ER_NOROUTE, ER_BEYONDSCOPE, ER_REJECTROUTE, ER_PARAMPROBLEM, ER_NOROUTE, ER_BEYONDSCOPE, ER_REJECTROUTE, ER_PARAMPROBLEM,

View File

@@ -179,6 +179,8 @@ static const char *pspectype2ascii(int type) {
return "ICMP"; return "ICMP";
case PS_ARP: case PS_ARP:
return "ARP"; return "ARP";
case PS_ND:
return "ND";
case PS_CONNECTTCP: case PS_CONNECTTCP:
return "connect"; return "connect";
default: default:
@@ -223,7 +225,7 @@ class UltraProbe {
public: public:
UltraProbe(); UltraProbe();
~UltraProbe(); ~UltraProbe();
enum UPType { UP_UNSET, UP_IP, UP_CONNECT, UP_RPC, UP_ARP } type; /* The type of probe this is */ enum UPType { UP_UNSET, UP_IP, UP_CONNECT, UP_RPC, UP_ARP, UP_ND } type; /* The type of probe this is */
/* Sets this UltraProbe as type UP_IP and creates & initializes the /* Sets this UltraProbe as type UP_IP and creates & initializes the
internal IPProbe. The relevent probespec is necessary for setIP internal IPProbe. The relevent probespec is necessary for setIP
@@ -235,6 +237,7 @@ public:
void setConnect(u16 portno); void setConnect(u16 portno);
/* Pass an arp packet, including ethernet header. Must be 42bytes */ /* Pass an arp packet, including ethernet header. Must be 42bytes */
void setARP(u8 *arppkt, u32 arplen); void setARP(u8 *arppkt, u32 arplen);
void setND(u8 *ndpkt, u32 ndlen);
// The 4 accessors below all return in HOST BYTE ORDER // The 4 accessors below all return in HOST BYTE ORDER
// source port used if TCP, UDP or SCTP // source port used if TCP, UDP or SCTP
u16 sport() const { u16 sport() const {
@@ -618,6 +621,7 @@ public:
bool prot_scan; bool prot_scan;
bool ping_scan; /* Includes trad. ping scan & arp scan */ bool ping_scan; /* Includes trad. ping scan & arp scan */
bool ping_scan_arp; /* ONLY includes arp ping scan */ bool ping_scan_arp; /* ONLY includes arp ping scan */
bool ping_scan_nd; /* ONLY includes ND ping scan */
bool noresp_open_scan; /* Whether no response means a port is open */ bool noresp_open_scan; /* Whether no response means a port is open */
/* massping state. */ /* massping state. */
@@ -759,6 +763,9 @@ static char *probespec2ascii(const probespec *pspec, char *buf, unsigned int buf
case PS_ARP: case PS_ARP:
Snprintf(buf, bufsz, "ARP"); Snprintf(buf, bufsz, "ARP");
break; break;
case PS_ND:
Snprintf(buf, bufsz, "ND");
break;
case PS_CONNECTTCP: case PS_CONNECTTCP:
Snprintf(buf, bufsz, "connect to port %hu", pspec->pd.tcp.dport); Snprintf(buf, bufsz, "connect to port %hu", pspec->pd.tcp.dport);
break; break;
@@ -802,6 +809,12 @@ void UltraProbe::setARP(u8 *arppkt, u32 arplen) {
return; return;
} }
void UltraProbe::setND(u8 *ndpkt, u32 ndlen) {
type = UP_ND;
mypspec.type = PS_ND;
return;
}
/* Sets this UltraProbe as type UP_IP and creates & initializes the /* Sets this UltraProbe as type UP_IP and creates & initializes the
internal IPProbe. The relevent probespec is necessary for setIP internal IPProbe. The relevent probespec is necessary for setIP
because pspec.type is ambiguous with just the ippacket (e.g. a because pspec.type is ambiguous with just the ippacket (e.g. a
@@ -1112,6 +1125,8 @@ static bool pingprobe_is_appropriate(const UltraScanInfo *USI,
return ((USI->ping_scan && !USI->ping_scan_arp )|| pingprobe->pd.icmp.type == 3); return ((USI->ping_scan && !USI->ping_scan_arp )|| pingprobe->pd.icmp.type == 3);
case(PS_ARP): case(PS_ARP):
return USI->ping_scan_arp; return USI->ping_scan_arp;
case(PS_ND):
return USI->ping_scan_nd;
} }
return false; return false;
} }
@@ -1400,7 +1415,7 @@ UltraScanInfo::~UltraScanInfo() {
Basically, any scan type except pure TCP connect scans are raw. */ Basically, any scan type except pure TCP connect scans are raw. */
bool UltraScanInfo::isRawScan() { bool UltraScanInfo::isRawScan() {
return scantype != CONNECT_SCAN return scantype != CONNECT_SCAN
&& (tcp_scan || udp_scan || sctp_scan || prot_scan || ping_scan_arp && (tcp_scan || udp_scan || sctp_scan || prot_scan || ping_scan_arp || ping_scan_nd
|| (ping_scan && (ptech.rawicmpscan || ptech.rawtcpscan || ptech.rawudpscan || (ping_scan && (ptech.rawicmpscan || ptech.rawtcpscan || ptech.rawudpscan
|| ptech.rawsctpscan || ptech.rawprotoscan))); || ptech.rawsctpscan || ptech.rawprotoscan)));
} }
@@ -1516,6 +1531,7 @@ static void set_default_port_state(vector<Target *> &targets, stype scantype) {
break; break;
case PING_SCAN: case PING_SCAN:
case PING_SCAN_ARP: case PING_SCAN_ARP:
case PING_SCAN_ND:
break; break;
default: default:
fatal("Unexpected scan type found in %s()", __func__); fatal("Unexpected scan type found in %s()", __func__);
@@ -1539,7 +1555,7 @@ void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, styp
SPM = new ScanProgressMeter(scantype2str(scantype)); SPM = new ScanProgressMeter(scantype2str(scantype));
send_rate_meter.start(&now); send_rate_meter.start(&now);
tcp_scan = udp_scan = sctp_scan = prot_scan = false; tcp_scan = udp_scan = sctp_scan = prot_scan = false;
ping_scan = noresp_open_scan = ping_scan_arp = false; ping_scan = noresp_open_scan = ping_scan_arp = ping_scan_nd = false;
memset((char *) &ptech, 0, sizeof(ptech)); memset((char *) &ptech, 0, sizeof(ptech));
switch(scantype) { switch(scantype) {
case FIN_SCAN: case FIN_SCAN:
@@ -1589,6 +1605,10 @@ void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, styp
ping_scan = true; ping_scan = true;
ping_scan_arp = true; ping_scan_arp = true;
break; break;
case PING_SCAN_ND:
ping_scan = true;
ping_scan_nd = true;
break;
default: default:
break; break;
} }
@@ -1624,7 +1644,7 @@ void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, styp
aren't doing a TCP connect scan, or if we're doing a ping scan that aren't doing a TCP connect scan, or if we're doing a ping scan that
requires it. */ requires it. */
if (isRawScan()) { if (isRawScan()) {
if (ping_scan_arp || ((o.sendpref & PACKET_SEND_ETH) && if (ping_scan_arp || (ping_scan_nd && o.sendpref != PACKET_SEND_IP_STRONG) || ((o.sendpref & PACKET_SEND_ETH) &&
Targets[0]->ifType() == devt_ethernet)) { Targets[0]->ifType() == devt_ethernet)) {
/* We'll send ethernet packets with dnet */ /* We'll send ethernet packets with dnet */
ethsd = eth_open_cached(Targets[0]->deviceName()); ethsd = eth_open_cached(Targets[0]->deviceName());
@@ -2020,6 +2040,12 @@ static int get_next_target_probe(UltraScanInfo *USI, HostScanStats *hss,
pspec->type = PS_ARP; pspec->type = PS_ARP;
hss->sent_arp = true; hss->sent_arp = true;
return 0; return 0;
} else if (USI->ping_scan_nd) {
if (hss->sent_arp)
return -1;
pspec->type = PS_ND;
hss->sent_arp = true;
return 0;
} else if (USI->ping_scan) { } else if (USI->ping_scan) {
/* This is ordered to try probes of higher effectiveness first: /* This is ordered to try probes of higher effectiveness first:
-PE -PS -PA -PP -PU -PE -PS -PA -PP -PU
@@ -2132,6 +2158,9 @@ int HostScanStats::freshPortsLeft() {
} else if (USI->ping_scan_arp) { } else if (USI->ping_scan_arp) {
if (sent_arp) return 0; if (sent_arp) return 0;
return 1; return 1;
} else if (USI->ping_scan_nd) {
if (sent_arp) return 0;
return 1;
} else if (USI->ping_scan) { } else if (USI->ping_scan) {
unsigned int num_probes = 0; unsigned int num_probes = 0;
if (USI->ptech.rawtcpscan) { if (USI->ptech.rawtcpscan) {
@@ -2566,7 +2595,7 @@ void HostScanStats::getTiming(struct ultra_timing_vals *tmng) {
preferred, is preferred, is
Raw TCP/SCTP (not filtered, not SYN/INIT to an open port) Raw TCP/SCTP (not filtered, not SYN/INIT to an open port)
ICMP information queries (echo request, timestamp request, netmask req) ICMP information queries (echo request, timestamp request, netmask req)
ARP ARP/ND
Raw TCP/SCTP (SYN/INIT to an open port) Raw TCP/SCTP (SYN/INIT to an open port)
UDP, IP protocol, or other ICMP (including filtered TCP/SCTP) UDP, IP protocol, or other ICMP (including filtered TCP/SCTP)
TCP connect TCP connect
@@ -2602,6 +2631,7 @@ static unsigned int pingprobe_score(const probespec *pspec, int state) {
score = 2; score = 2;
break; break;
case PS_ARP: case PS_ARP:
case PS_ND:
score = 4; score = 4;
break; break;
case PS_UDP: case PS_UDP:
@@ -3159,6 +3189,75 @@ static UltraProbe *sendArpScanProbe(UltraScanInfo *USI, HostScanStats *hss,
return probe; return probe;
} }
static UltraProbe *sendNDScanProbe(UltraScanInfo *USI, HostScanStats *hss,
u8 tryno, u8 pingseq) {
UltraProbe *probe = new UltraProbe();
struct eth_nfo eth;
struct eth_nfo *ethptr = NULL;
u8 *packet = NULL;
u32 packetlen = 0;
struct in6_addr ns_dst_ip6;
ns_dst_ip6 = *hss->target->v6hostip();
if (USI->ethsd) {
unsigned char ns_dst_mac[6] = {0x33, 0x33, 0xff};
ns_dst_mac[3] = ns_dst_ip6.s6_addr[13];
ns_dst_mac[4] = ns_dst_ip6.s6_addr[14];
ns_dst_mac[5] = ns_dst_ip6.s6_addr[15];
memcpy(eth.srcmac, hss->target->SrcMACAddress(), 6);
memcpy(eth.dstmac, ns_dst_mac, 6);
eth.ethsd = USI->ethsd;
eth.devname[0] = '\0';
ethptr = &eth;
}
unsigned char multicast_prefix[13] = {0};
multicast_prefix[0] = 0xff;
multicast_prefix[1] = 0x02;
multicast_prefix[11] = 0x1;
multicast_prefix[12] = 0xff;
memcpy(&ns_dst_ip6, multicast_prefix, sizeof(multicast_prefix));
struct sockaddr_storage source;
struct sockaddr_in6 *sin6;
size_t source_len;
source_len = sizeof(source);
hss->target->SourceSockAddr(&source, &source_len);
sin6 = (struct sockaddr_in6 *) &source;
struct icmpv6_msg_nd ns_msg;
ns_msg.icmpv6_flags = htons(0);
memcpy(&ns_msg.icmpv6_target, hss->target->v6hostip(), IP6_ADDR_LEN);
ns_msg.icmpv6_option_type = 1;
ns_msg.icmpv6_option_length = 1;
memcpy(&ns_msg.icmpv6_mac, hss->target->SrcMACAddress(), ETH_ADDR_LEN);
packet = build_icmpv6_raw(&sin6->sin6_addr, &ns_dst_ip6,
0, 0, o.ttl, 0, 0, ICMPV6_NEIGHBOR_SOLICITATION,
0, (char *)&ns_msg, sizeof(ns_msg),
&packetlen);
probe->sent = USI->now;
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
probe->tryno = tryno;
probe->pingseq = pingseq;
/* First build the probe */
probe->setND(packet, packetlen);
free(packet);
/* Now that the probe has been sent, add it to the Queue for this host */
hss->probes_outstanding.push_back(probe);
USI->gstats->num_probes_active++;
hss->num_probes_active++;
gettimeofday(&USI->now, NULL);
return probe;
}
/* Build an appropriate protocol scan (-sO) probe for the given source and /* Build an appropriate protocol scan (-sO) probe for the given source and
destination addresses and protocol. src and dst must be of the same address destination addresses and protocol. src and dst must be of the same address
@@ -3559,6 +3658,8 @@ static void sendNextScanProbe(UltraScanInfo *USI, HostScanStats *hss) {
USI->gstats->probes_sent++; USI->gstats->probes_sent++;
if (pspec.type == PS_ARP) if (pspec.type == PS_ARP)
sendArpScanProbe(USI, hss, 0, 0); sendArpScanProbe(USI, hss, 0, 0);
else if (pspec.type == PS_ND)
sendNDScanProbe(USI, hss, 0, 0);
else if (pspec.type == PS_CONNECTTCP) else if (pspec.type == PS_CONNECTTCP)
sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, 0, 0); sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, 0, 0);
else if (pspec.type == PS_TCP || pspec.type == PS_UDP else if (pspec.type == PS_TCP || pspec.type == PS_UDP
@@ -3584,7 +3685,7 @@ static void sendNextRetryStackProbe(UltraScanInfo *USI, HostScanStats *hss) {
if (pspec.type == PS_CONNECTTCP) if (pspec.type == PS_CONNECTTCP)
sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, pspec_tries + 1, 0); sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, pspec_tries + 1, 0);
else { else {
assert(pspec.type != PS_ARP); assert(pspec.type != PS_ARP and pspec.type != PS_ND);
sendIPScanProbe(USI, hss, &pspec, pspec_tries + 1, 0); sendIPScanProbe(USI, hss, &pspec, pspec_tries + 1, 0);
} }
} }
@@ -3653,6 +3754,8 @@ static void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
sendIPScanProbe(USI, hss, &hss->target->pingprobe, 0, hss->nextPingSeq(true)); sendIPScanProbe(USI, hss, &hss->target->pingprobe, 0, hss->nextPingSeq(true));
} else if (hss->target->pingprobe.type == PS_ARP) { } else if (hss->target->pingprobe.type == PS_ARP) {
sendArpScanProbe(USI, hss, 0, hss->nextPingSeq(true)); sendArpScanProbe(USI, hss, 0, hss->nextPingSeq(true));
} else if (hss->target->pingprobe.type == PS_ND) {
sendNDScanProbe(USI, hss, 0, hss->nextPingSeq(true));
} else if (USI->scantype == RPC_SCAN) { } else if (USI->scantype == RPC_SCAN) {
assert(0); /* TODO: fill out */ assert(0); /* TODO: fill out */
} else { } else {
@@ -3738,6 +3841,8 @@ static void retransmitProbe(UltraScanInfo *USI, HostScanStats *hss,
newProbe = sendConnectScanProbe(USI, hss, probe->pspec()->pd.tcp.dport, probe->tryno + 1, 0); newProbe = sendConnectScanProbe(USI, hss, probe->pspec()->pd.tcp.dport, probe->tryno + 1, 0);
} else if (probe->type == UltraProbe::UP_ARP) { } else if (probe->type == UltraProbe::UP_ARP) {
newProbe = sendArpScanProbe(USI, hss, probe->tryno + 1, 0); newProbe = sendArpScanProbe(USI, hss, probe->tryno + 1, 0);
} else if (probe->type == UltraProbe::UP_ND) {
newProbe = sendNDScanProbe(USI, hss, probe->tryno + 1, 0);
} else { } else {
/* TODO: Support any other probe types */ /* TODO: Support any other probe types */
fatal("%s: unsupported probe type %d", __func__, probe->type); fatal("%s: unsupported probe type %d", __func__, probe->type);
@@ -4171,6 +4276,75 @@ static bool get_arp_result(UltraScanInfo *USI, struct timeval *stime) {
return gotone; return gotone;
} }
static bool get_ns_result(UltraScanInfo *USI, struct timeval *stime) {
gettimeofday(&USI->now, NULL);
long to_usec;
int rc;
u8 rcvdmac[6];
struct sockaddr_in6 rcvdIP;
struct timeval rcvdtime;
bool timedout = false;
bool has_mac = false;
struct sockaddr_in6 sin6;
HostScanStats *hss = NULL;
list<UltraProbe *>::iterator probeI;
int gotone = 0;
do {
to_usec = TIMEVAL_SUBTRACT(*stime, USI->now);
if (to_usec < 2000) to_usec = 2000;
rc = read_na_pcap(USI->pd, rcvdmac, &rcvdIP, to_usec, &rcvdtime, &has_mac);
gettimeofday(&USI->now, NULL);
if (rc == -1) fatal("Received -1 response from read_arp_reply_pcap");
if (rc == 0) {
if (TIMEVAL_SUBTRACT(*stime, USI->now) < 0) {
timedout = true;
break;
} else continue;
}
if (rc == 1) {
if (TIMEVAL_SUBTRACT(USI->now, *stime) > 200000) {
/* While packets are still being received, I'll be generous
and give an extra 1/5 sec. But we have to draw the line
somewhere. Hopefully this response will be a keeper so it
won't matter. */
timedout = true;
}
/* Yay, I got one. Find whether I asked for it */
/* Search for this host on the incomplete list */
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_addr = rcvdIP.sin6_addr;
sin6.sin6_family = AF_INET6;
hss = USI->findHost((struct sockaddr_storage *) &sin6);
if (!hss) continue;
/* Add found HW address for target */
/* A Neighbor Advertisement packet may not include the Target link-layer address. */
if (has_mac){
hss->target->setMACAddress(rcvdmac);
}
hss->target->reason.reason_id = ER_NDRESPONSE;
if (hss->probes_outstanding.empty()) {
continue;
/* TODO: I suppose I should really mark the @@# host as up */
}
probeI = hss->probes_outstanding.end();
probeI--;
ultrascan_host_probe_update(USI, hss, probeI, HOST_UP, &rcvdtime);
/* Now that we know the host is up, we can forget our other probes. */
hss->destroyAllOutstandingProbes();
/* TODO: Set target mac */
gotone = 1;
// printf("Marked host %s as up!", hss->target->NameIP());
break;
}
} while(!timedout);
return gotone;
}
/* Tries to get one *good* (finishes a probe) pcap response by the /* Tries to get one *good* (finishes a probe) pcap response by the
@@ -5254,6 +5428,8 @@ static void waitForResponses(UltraScanInfo *USI) {
USI->sendOK(&stime); USI->sendOK(&stime);
if (USI->ping_scan_arp) { if (USI->ping_scan_arp) {
gotone = get_arp_result(USI, &stime); gotone = get_arp_result(USI, &stime);
} else if (USI->ping_scan_nd) {
gotone = get_ns_result(USI,&stime);
} else if (USI->ping_scan) { } else if (USI->ping_scan) {
if (USI->pd) if (USI->pd)
gotone = get_ping_pcap_result(USI, &stime); gotone = get_ping_pcap_result(USI, &stime);
@@ -5315,6 +5491,16 @@ static void begin_sniffer(UltraScanInfo *USI, vector<Target *> &Targets) {
pcap_filter += " and arp[22:2] = 0x"; pcap_filter += " and arp[22:2] = 0x";
pcap_filter.append(macstring, 4 * 2, 2 * 2); pcap_filter.append(macstring, 4 * 2, 2 * 2);
//its not arp, so lets check if for a protocol scan. //its not arp, so lets check if for a protocol scan.
} else if (USI->ping_scan_nd) {
/* Libpcap: IPv6 upper-layer protocol is not supported by proto[x] */
/* Grab the ICMPv6 type using ip6[X:Y] syntax. This works only if there are no
extension headers (top-level nh is IPPROTO_ICMPV6). */
const u8 *srcmac = Targets[0]->SrcMACAddress();
assert(srcmac);
char filterstr[256];
Snprintf(filterstr, 256, "icmp6 and ip6[6:1] = %u and ip6[40:1] = %u",
IPPROTO_ICMPV6, ICMPV6_NEIGHBOR_ADVERTISEMENT);
pcap_filter.append(filterstr);
} else if(USI->prot_scan || (USI->ping_scan && USI->ptech.rawprotoscan)){ } else if(USI->prot_scan || (USI->ping_scan && USI->ptech.rawprotoscan)){
struct sockaddr_storage source; struct sockaddr_storage source;
size_t source_len; size_t source_len;

View File

@@ -131,6 +131,7 @@ struct probespec_icmpv6data {
#define PS_CONNECTTCP 6 #define PS_CONNECTTCP 6
#define PS_SCTP 7 #define PS_SCTP 7
#define PS_ICMPV6 8 #define PS_ICMPV6 8
#define PS_ND 9
/* The size of this structure is critical, since there can be tens of /* The size of this structure is critical, since there can be tens of
thousands of them stored together ... */ thousands of them stored together ... */

View File

@@ -118,7 +118,7 @@ static void arpping(Target *hostbatch[], int num_hosts) {
/* Default timout should be much lower for arp */ /* Default timout should be much lower for arp */
hostbatch[targetno]->to.timeout = MAX(o.minRttTimeout(), MIN(o.initialRttTimeout(), INITIAL_ARP_RTT_TIMEOUT)) * 1000; hostbatch[targetno]->to.timeout = MAX(o.minRttTimeout(), MIN(o.initialRttTimeout(), INITIAL_ARP_RTT_TIMEOUT)) * 1000;
if (!hostbatch[targetno]->SrcMACAddress()) { if (!hostbatch[targetno]->SrcMACAddress()) {
bool islocal = islocalhost(hostbatch[targetno]->v4hostip()); bool islocal = islocalhost(hostbatch[targetno]->TargetSockAddr());
if (islocal) { if (islocal) {
log_write(LOG_STDOUT|LOG_NORMAL, log_write(LOG_STDOUT|LOG_NORMAL,
"ARP ping: Considering %s UP because it is a local IP, despite no MAC address for device %s\n", "ARP ping: Considering %s UP because it is a local IP, despite no MAC address for device %s\n",
@@ -136,7 +136,10 @@ static void arpping(Target *hostbatch[], int num_hosts) {
targets.push_back(hostbatch[targetno]); targets.push_back(hostbatch[targetno]);
} }
if (!targets.empty()) if (!targets.empty())
ultra_scan(targets, NULL, PING_SCAN_ARP); if (targets[0]->af() == AF_INET)
ultra_scan(targets, NULL, PING_SCAN_ARP);
else
ultra_scan(targets, NULL, PING_SCAN_ND);
return; return;
} }
@@ -419,6 +422,16 @@ batchfull:
arpping_done = true; arpping_done = true;
} }
/* No other interface types are supported by ND ping except devt_ethernet
at the moment. */
if (hs->hostbatch[0]->ifType() == devt_ethernet &&
hs->hostbatch[0]->af() == AF_INET6 &&
hs->hostbatch[0]->directlyConnected() &&
o.sendpref != PACKET_SEND_IP_STRONG) {
arpping(hs->hostbatch, hs->current_batch_sz);
arpping_done = true;
}
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if ((o.sendpref & PACKET_SEND_ETH) && if ((o.sendpref & PACKET_SEND_ETH) &&
hs->hostbatch[0]->ifType() == devt_ethernet) { hs->hostbatch[0]->ifType() == devt_ethernet) {

View File

@@ -1093,11 +1093,9 @@ u8 *build_icmpv6_raw(const struct in6_addr *source,
packet, icmplen, packetlen); packet, icmplen, packetlen);
free(packet); free(packet);
return ipv6; return ipv6;
} }
/* Builds an IGMP packet (including an IP header) by packing the fields /* Builds an IGMP packet (including an IP header) by packing the fields
with the given information. It allocates a new buffer to store the with the given information. It allocates a new buffer to store the
packet contents, and then returns that buffer. The packet is not 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; 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 // Returns whether the packet receive time value obtained from libpcap
// (and thus by readip_pcap()) should be considered valid. When // (and thus by readip_pcap()) should be considered valid. When

View File

@@ -638,6 +638,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);
int read_na_pcap(pcap_t *pd, u8 *sendermac, struct sockaddr_in6 *senderIP, long to_usec,
struct timeval *rcvdtime, bool *has_mac);
/* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap /* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap
descriptor pd. If it receives one, fills in sendermac (must pass 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) in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)