diff --git a/CHANGELOG b/CHANGELOG
index e5ebedcf1..b1df3adea 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,9 @@
# Nmap Changelog ($Id$); -*-text-*-
+o [NSE] Added the targets-sniffer script by Nick Nickolaou. It sniffs
+ on an interface for a configurable amount of time, then displays the
+ IPv4 addresses found and optionally adds them to the scanning queue.
+
o [NSE] Added nmap.get_interface and nmap.get_interface_info functions
so scripts can access characteristics of the scanning interface.
[Djalal]
diff --git a/scripts/script.db b/scripts/script.db
index 51d541a04..78fb911e3 100644
--- a/scripts/script.db
+++ b/scripts/script.db
@@ -177,6 +177,7 @@ Entry { filename = "ssl-known-key.nse", categories = { "discovery", "safe", "vul
Entry { filename = "sslv2.nse", categories = { "default", "safe", } }
Entry { filename = "stuxnet-detect.nse", categories = { "discovery", "intrusive", } }
Entry { filename = "svn-brute.nse", categories = { "auth", "intrusive", } }
+Entry { filename = "targets-sniffer.nse", categories = { "discovery", } }
Entry { filename = "targets-traceroute.nse", categories = { "discovery", "safe", } }
Entry { filename = "telnet-brute.nse", categories = { "auth", "intrusive", } }
Entry { filename = "upnp-info.nse", categories = { "default", "discovery", "safe", } }
diff --git a/scripts/targets-sniffer.nse b/scripts/targets-sniffer.nse
new file mode 100644
index 000000000..0eb28ab84
--- /dev/null
+++ b/scripts/targets-sniffer.nse
@@ -0,0 +1,139 @@
+-- -*- mode: lua -*-:
+-- vim: set filetype=lua :
+
+description = [[
+Sniffs the local network for a configurable amount of time and prints
+discovered addresses. If newtargets is true, adds the addresses to
+the queue to be scanned.
+
+Requires root privileges. Either the targets-sniffer.iface script
+argument or -e Nmap option to define which interface to use.
+]]
+
+---
+-- @usage
+-- nmap -sL --script=targets-sniffer --script-args=newtargets,targets-sniffer.timeout=5s,targets-sniffer.iface=eth0
+-- @args targets-sniffer.timeout The amount of time to listen for packets. Default 10s.
+-- @args targets-sniffer.iface The interface to use for sniffing.
+-- @args newtargets If true, add discovered targets to the scan queue.
+-- @output
+-- Pre-scan script results:
+-- | targets-sniffer:
+-- | 192.168.0.1
+-- | 192.168.0.3
+-- | 192.168.0.35
+-- |_192.168.0.100
+
+
+-- Thanks to everyone for the feedback and especially Henri Doreau for his detailed feedback and suggestions
+
+author = "Nick Nikolaou "
+categories = {"discovery"}
+license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
+
+require("stdnse")
+require("target")
+require("nmap")
+require("packet")
+require("bin")
+
+local interface_info
+local all_addresses= {}
+local unique_addresses = {}
+
+--Make sure the IP is not a broadcast or the local address
+local function check_if_valid(address)
+ local broadcast = interface_info.broadcast
+ local local_address = interface_info.address
+
+ if address == local_address or address == broadcast or address == "255.255.255.255" then
+ return false
+ else
+ return true end
+end
+
+local function get_ip_addresses(layer3)
+ local ip = packet.Packet:new(layer3, layer3:len())
+ return packet.toip(ip.ip_bin_src),packet.toip(ip.ip_bin_dst)
+end
+
+prerule = function()
+ return true
+end
+
+
+action = function()
+
+ local sock = nmap.new_socket()
+ local ip_src,ip_dst
+ local packet_counter = 0
+ local ip_counter = 0
+ local DEFAULT_TIMEOUT_SEC = 10 -- Default timeout value in seconds if the timeout argument is not specified
+ local timeoutstr = stdnse.get_script_args("targets-sniffer.timeout") or tostring(DEFAULT_TIMEOUT_SEC)
+ local timeout = (stdnse.parse_timespec(timeoutstr) * 1000)
+ local interface = stdnse.get_script_args("targets-sniffer.iface") or nmap.get_interface()
+ interface_info = nmap.get_interface_info(interface)
+
+ if interface_info==nil then -- Check if we have the interface information
+ stdnse.print_debug(1,"Error: Unable to get interface info. Did you specify the correct interface using 'targets-sniffer.iface=' or '-e '?")
+ return
+ end
+
+
+ if sock==nil then
+ stdnse.print_debug(1,"Error - unable to open socket using interface %s",interface)
+ return
+ else
+ sock:pcap_open(interface, 104, false , "ip")
+ stdnse.print_debug(1, "Will sniff for %s seconds on interface %s.", (timeout/1000),interface)
+
+ repeat
+
+ local start_time = nmap.clock_ms() -- Used for script timeout
+ sock:set_timeout(timeout)
+ local status, _, _, layer3 = sock:pcap_receive()
+
+ if status then
+
+ packet_counter=packet_counter+1
+ ip_src,ip_dst = get_ip_addresses(layer3)
+ stdnse.print_debug(1,"Got IP addresses %s and %s",ip_src,ip_dst)
+
+ if check_if_valid(ip_src) == true then
+ if not unique_addresses[ip_src] then
+ unique_addresses[ip_src] = true
+ table.insert(all_addresses,ip_src)
+ end
+ end
+
+
+ if check_if_valid(ip_dst) == true then
+ if not unique_addresses[ip_dst] then
+ unique_addresses[ip_dst] = true
+ table.insert(all_addresses,ip_dst)
+ end
+ end
+
+ end
+ -- Update timeout
+ timeout = timeout - (nmap.clock_ms() - start_time)
+
+ until timeout <= 0
+
+ sock:pcap_close()
+ end
+
+ if target.ALLOW_NEW_TARGETS == true then
+ for _,v in pairs(all_addresses) do
+ target.add(v)
+ end
+ else
+ stdnse.print_debug(1,"Not adding targets to newtargets. If you want to do that use the 'newtargets' script argument.")
+ end
+
+ if #all_addresses>0 then
+ stdnse.print_debug(1,"Added %s address(es) to newtargets", #all_addresses)
+ end
+
+ return string.format("Sniffed %s address(es). \n", #all_addresses) .. stdnse.strjoin("\n",all_addresses)
+end