diff --git a/CHANGELOG b/CHANGELOG
index af7880d4a..0a69b64e8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,8 @@
# Nmap Changelog ($Id$); -*-text-*-
+o [NSE] Added host based registry, which allows scripts to share data between
+ scripts scanning a specific host. [Patrik]
+
o [NSE] Applied patch from Andrew Orr that fixes the recent changes in the
BitCoin protocol. [Patrik]
diff --git a/docs/scripting.xml b/docs/scripting.xml
index bc2e1bbb1..a7c45a3c1 100644
--- a/docs/scripting.xml
+++ b/docs/scripting.xml
@@ -2147,34 +2147,46 @@ try(socket:send(result))
The Registryregistry (NSE)
-
- The registry is a Lua table (accessible
- as nmap.registry) with the special property
- that it is visible by all scripts and retains its state
- between script executions. The registry is transient—it
- is not stored between Nmap executions. Every script can read
- and write to the registry. Scripts commonly use it to save
- information for other instances of the same script. For
- example, the whois
- and asn-query scripts may query one IP
- address, but receive information which may apply to tens of
- thousands of IPs on that network. Saving the information in
- the registry may prevent other script threads from having to
- repeat the query.
+ Scripts can share information by stroring values in a
+ register, which is a special table that can be
+ accessed by all scripts. There is a global registry with the name
+ nmap.registry, shared by all scripts. Each host
+ additionally has its own registry called
+ host.registry, where host is the
+ host table passed to a script.
+ Information in the registries is not stored between Nmap
+ executions.
- The registry may also be used to hand
- information to completely different scripts. For example,
- the snmp-brute script saves a discovered
- community name in the registry where it may be used by other
- SNMP scripts. Script which use the results of another script
- must declare it using the dependencies
- variable to make sure that the earlier script runs first.
-
+ The global registry persists throughout an entire scan session.
+ Scripts can use it, for example, to store values that will later be
+ displayed by a postrule script. The per-host registries, on the other
+ hand, only exist while a host is being scanned. They can be used to send
+ information from one script to another one that runs against the same
+ host. When possible, use the per-host registry; this not only saves you
+ from having to make key names unique across hosts, but also allows the
+ memory used by the registry to be reclaimed when it is no longer
+ needed.
- Because every script can write to the registry table, it
- is important to avoid conflicts by choosing keys wisely
- (uniquely).
+
+ Here are examples of using both registries:
+
+ The portrule of the ssh-hostkey script collects SSH key fingerprints
+ and stores them in the global nmap.registry so they
+ can be printed later by the postrule.
+ The ssl-cert script collects SSL certificates and
+ stores them in the per-host registry so that the
+ ssl-google-cert-catalog script can use them without
+ having to make another connection to the server.
+
+
+ Because every script can write to the global registry table, it is
+ important to make the keys you use unique, to avoid overwriting the keys
+ of other scripts (or the same script running in parallel).
+
+ Scripts that use the results of another script must declare it using
+ the dependencies variable to make sure that the earlier
+ script runs first.
diff --git a/nse_main.lua b/nse_main.lua
index b4b923f82..595e8db24 100644
--- a/nse_main.lua
+++ b/nse_main.lua
@@ -219,6 +219,13 @@ local function tcopy (t)
return tc;
end
+-- copies the host table while preserving the registry
+local function host_copy(t)
+ local h = tcopy(t)
+ h.registry = t.registry
+ return h
+end
+
local REQUIRE_ERROR = {};
rawset(stdnse, "silent_require", function (...)
local status, mod = pcall(require, ...);
@@ -1179,18 +1186,18 @@ local function main (hosts, scantype)
-- Check hostrules for this host.
for j, host in ipairs(hosts) do
for _, script in ipairs(scripts) do
- local thread = script:new_thread("hostrule", tcopy(host));
+ local thread = script:new_thread("hostrule", host_copy(host));
if thread then
- thread.args, thread.host = {n = 1, tcopy(host)}, host;
+ thread.args, thread.host = {n = 1, host_copy(host)}, host;
yield(thread);
end
end
-- Check portrules for this host.
for port in cnse.ports(host) do
for _, script in ipairs(scripts) do
- local thread = script:new_thread("portrule", tcopy(host), tcopy(port));
+ local thread = script:new_thread("portrule", host_copy(host), tcopy(port));
if thread then
- thread.args, thread.host, thread.port = {n = 2, tcopy(host), tcopy(port)}, host, port;
+ thread.args, thread.host, thread.port = {n = 2, host_copy(host), tcopy(port)}, host, port;
yield(thread);
end
end
diff --git a/nse_nmaplib.cc b/nse_nmaplib.cc
index 11b671f00..f09483821 100644
--- a/nse_nmaplib.cc
+++ b/nse_nmaplib.cc
@@ -154,6 +154,9 @@ void set_hostinfo(lua_State *L, Target *currenths) {
setnfield(L, -1, "timeout", (lua_Number) currenths->to.timeout / 1000000.0);
lua_setfield(L, -2, "times");
+ lua_newtable(L);
+ lua_setfield(L, -2, "registry");
+
/* add distance (in hops) if traceroute has been performed */
if (currenths->traceroute_hops.size() > 0)
{