Nmap's scripting engine consists of three more or less distinct
parts. The largest part is the embeddable Lua interpreter. This
is a lightweight language designed for extensibility. It offers
a powerful and well documented API for interfacing with other
software (such as Nmap).
The second part of the Nmap scripting engine is the NSE library, which
connects Lua and Nmap. This layer
handles issues such as initialization of the Lua interpreter,
scheduling of parallel script execution, script retrieval and
more. It is also the heart of the NSE network I/O framework and the
exception handling mechanism.
Lua was designed with a small feature set to ease embedding. So
we have added extensions to support more specialized
functionality. These basically are
Lua modules written either in Lua itself, or where needed in C. This
NSE library is the third part of the NSE.
The Nmap scripting language is an embedded Lua interpreter which was
extended with libraries for interfacing with Nmap. The Nmap
API is in the Lua namespace nmap
. This
means that all calls to resources provided by Nmap have an
nmap
prefix.
nmap.new_socket()
, for example, returns a
new socket wrapper object. The Nmap library layer also takes
care of initializing the Lua context, scheduling parallel
scripts and collecting the output produced by completed
scripts.
During the planning stages, we considered several programming
languages as the bases for Nmap scripting. One option was to
implement a completely new programming language. The criteria
imposed on the options were strict, NSE needed to be easy to
use, small in size, compatible with the Nmap license,
scalable, fast and parallelizable. There have been several
efforts to design a security auditing language from scratch
which have resulted in well known awkward solutions. It was
clear from the beginning that we would not go down this
road. For a while the Guile scheme interpreter was considered
but the preference drifted towards Elk in favor of its more
liberal license. But parallelizing Elk scripts would have been
difficult. In addition, the subset of Nmap users familiar with
functional programming is regarded too small to consider
Scheme as an option. Larger interpreters like Perl, Python or
Ruby are well known and loved, but are difficult to embed
efficiently. In the end, Lua exceeded in all criteria for
NSE. It is small, distributed under the MIT license, has
coroutines which provide a sane method for parallel script
execution, was designed with embeddability in mind, has
excellent documentation, and is actively developed by a large
and committed community.