mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
o [NSE] Added broadcast-ripng-discover that discovers IPv6 RIPng routers and
displays their routing information. [Patrik]
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o [NSE] Added broadcast-ripng-discover that discovers IPv6 RIPng routers and
|
||||
displays their routing information. [Patrik]
|
||||
|
||||
o [NSE] Made gathered CPE codes available to NSE. [Henri]
|
||||
|
||||
o [NSE] Fixed a memory leak in PortList::setServiceProbeResults() noticed and
|
||||
|
||||
211
scripts/broadcast-ripng-discover.nse
Normal file
211
scripts/broadcast-ripng-discover.nse
Normal file
@@ -0,0 +1,211 @@
|
||||
description = [[
|
||||
Discovers hosts and routing information from devices running RIPng on the
|
||||
LAN. It does so by sending a RIPng Request command and collects the responses
|
||||
from all devices responding to the request.
|
||||
]]
|
||||
|
||||
---
|
||||
-- @usage
|
||||
-- nmap --script broadcast-ripng-discover
|
||||
--
|
||||
-- @output
|
||||
-- | broadcast-ripng-discover:
|
||||
-- | fe80::a00:27ff:fe9a:880c
|
||||
-- | route metric next hop
|
||||
-- | fe80:470:0:0:0:0:0:0/64 1
|
||||
-- | fe80:471:0:0:0:0:0:0/64 1
|
||||
-- |_ fe80:472:0:0:0:0:0:0/64 1
|
||||
--
|
||||
-- @args broadcast-ripng-discover.timeout sets the connection timeout in ms
|
||||
-- (default: 5000ms)
|
||||
|
||||
author = "Patrik Karlsson"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"broadcast", "safe"}
|
||||
|
||||
require 'ipOps'
|
||||
require 'tab'
|
||||
|
||||
prerule = function() return ( nmap.address_family() == "inet6" ) end
|
||||
|
||||
RIPng = {
|
||||
|
||||
-- Supported RIPng commands
|
||||
Command = {
|
||||
Request = 1,
|
||||
Response = 2,
|
||||
},
|
||||
|
||||
-- Route table entry
|
||||
RTE = {
|
||||
|
||||
-- Creates a new Route Table Entry
|
||||
-- @param prefix string containing the ipv6 route prefix
|
||||
-- @param tag number containing the route tag
|
||||
-- @param prefix_len number containing the length in bits of the
|
||||
-- signifcant part of the prefix
|
||||
-- @param metric number containing the current metric for the
|
||||
-- destination
|
||||
new = function(self, prefix, tag, prefix_len, metric)
|
||||
local o = {
|
||||
prefix = prefix,
|
||||
tag = tag,
|
||||
prefix_len = prefix_len,
|
||||
metric = metric
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
-- Parses a byte string and creates an instance of RTE
|
||||
-- @param data string of bytes
|
||||
-- @return rte instance of RTE
|
||||
parse = function(data)
|
||||
local rte = RIPng.RTE:new()
|
||||
local pos, ip
|
||||
|
||||
pos, ip, rte.tag, rte.prefix_len, rte.metric = bin.unpack(">A16SCC", data)
|
||||
ip = select(2, bin.unpack("B" .. #ip, ip))
|
||||
rte.prefix = ipOps.bin_to_ip(ip)
|
||||
return rte
|
||||
end,
|
||||
|
||||
-- Converts a RTE instance to string
|
||||
-- @return string of bytes to send to the server
|
||||
__tostring = function(self)
|
||||
local ipstr = ipOps.ip_to_str(self.prefix)
|
||||
assert(16 == #ipstr, "Invalid IPv6 address encountered")
|
||||
return bin.pack(">ASCC", ipstr, self.tag, self.prefix_len, self.metric)
|
||||
end,
|
||||
|
||||
|
||||
},
|
||||
|
||||
-- The Request class contains functions to build a RIPv2 Request
|
||||
Request = {
|
||||
|
||||
-- Creates a new Request instance
|
||||
--
|
||||
-- @param command number containing the RIPv2 Command to use
|
||||
-- @return o instance of request
|
||||
new = function(self, entries)
|
||||
local o = {
|
||||
command = 1,
|
||||
version = 1,
|
||||
entries = entries,
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
-- Converts the whole request to a string
|
||||
__tostring = function(self)
|
||||
local RESERVED = 0
|
||||
local str = bin.pack(">CCS", self.command, self.version, RESERVED)
|
||||
for _, rte in ipairs(self.entries) do
|
||||
str = str .. tostring(rte)
|
||||
end
|
||||
return str
|
||||
end,
|
||||
|
||||
},
|
||||
|
||||
-- A RIPng Response
|
||||
Response = {
|
||||
|
||||
-- Creates a new Response instance
|
||||
-- @return o new instance of Response
|
||||
new = function(self)
|
||||
local o = { }
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
|
||||
-- Creates a new Response instance based on a string of bytes
|
||||
-- @return resp new instance of Response
|
||||
parse = function(data)
|
||||
local resp = RIPng.Response:new()
|
||||
local pos, _
|
||||
|
||||
pos, resp.command, resp.version, _ = bin.unpack(">CCS", data)
|
||||
resp.entries = {}
|
||||
while( pos < #data ) do
|
||||
local e = RIPng.RTE.parse(data:sub(pos))
|
||||
table.insert(resp.entries, e)
|
||||
pos = pos + 20
|
||||
end
|
||||
|
||||
return resp
|
||||
end,
|
||||
}
|
||||
}
|
||||
|
||||
local function fail(err) return ("\n ERROR: %s"):format(err or "") end
|
||||
|
||||
-- Parses a RIPng response
|
||||
-- @return ret string containing the routing table
|
||||
local function parse_response(resp)
|
||||
local next_hop
|
||||
local result = tab.new(3)
|
||||
tab.addrow(result, "route", "metric", "next hop")
|
||||
for _, rte in pairs(resp.entries or {}) do
|
||||
-- next hop information is specified in a separate RTE according to
|
||||
-- RFC 2080 section 2.1.1
|
||||
if ( 0xFF == rte.metric ) then
|
||||
next_hop = rte.prefix
|
||||
else
|
||||
tab.addrow(result, ("%s/%d"):format(rte.prefix, rte.prefix_len), rte.metric, next_hop or "")
|
||||
end
|
||||
end
|
||||
return tab.dump(result)
|
||||
end
|
||||
|
||||
action = function()
|
||||
|
||||
local req = RIPng.Request:new( { RIPng.RTE:new("0::", 0, 0, 16) } )
|
||||
local host, port = "FF02::9", { number = 521, protocol = "udp" }
|
||||
local iface = nmap.get_interface()
|
||||
local timeout = stdnse.get_script_args(SCRIPT_NAME..".timeout") or 5000
|
||||
|
||||
local sock = nmap.new_socket("udp")
|
||||
sock:bind(nil, 521)
|
||||
sock:set_timeout(timeout)
|
||||
|
||||
local status = sock:sendto(host, port, tostring(req))
|
||||
|
||||
-- do we need to add the interface name to the address?
|
||||
if ( not(status) ) then
|
||||
if ( not(iface) ) then
|
||||
return fail("Couldn't determine what interface to use, try supplying it with -e")
|
||||
end
|
||||
status = sock:sendto(host .. "%" .. iface, port, tostring(req))
|
||||
end
|
||||
|
||||
if ( not(status) ) then
|
||||
return fail("Failed to send request to server")
|
||||
end
|
||||
|
||||
local responses = {}
|
||||
while(true) do
|
||||
local status, data = sock:receive()
|
||||
if ( not(status) ) then
|
||||
break
|
||||
else
|
||||
local status, _, _, rhost = sock:get_info()
|
||||
if ( not(status) ) then
|
||||
rhost = "unknown"
|
||||
end
|
||||
responses[rhost] = RIPng.Response.parse(data)
|
||||
end
|
||||
end
|
||||
|
||||
local result = {}
|
||||
for ip, resp in pairs(responses) do
|
||||
print(ip, resp)
|
||||
table.insert(result, { name = ip, parse_response(resp) } )
|
||||
end
|
||||
return stdnse.format_output(true, result)
|
||||
end
|
||||
@@ -29,6 +29,7 @@ Entry { filename = "broadcast-pc-duo.nse", categories = { "broadcast", "safe", }
|
||||
Entry { filename = "broadcast-ping.nse", categories = { "broadcast", "discovery", "safe", } }
|
||||
Entry { filename = "broadcast-pppoe-discover.nse", categories = { "broadcast", "safe", } }
|
||||
Entry { filename = "broadcast-rip-discover.nse", categories = { "broadcast", "safe", } }
|
||||
Entry { filename = "broadcast-ripng-discover.nse", categories = { "broadcast", "safe", } }
|
||||
Entry { filename = "broadcast-sybase-asa-discover.nse", categories = { "broadcast", "safe", } }
|
||||
Entry { filename = "broadcast-upnp-info.nse", categories = { "broadcast", "safe", } }
|
||||
Entry { filename = "broadcast-wake-on-lan.nse", categories = { "broadcast", "safe", } }
|
||||
|
||||
Reference in New Issue
Block a user