Index: nmap.standalone.lua =================================================================== --- nmap.standalone.lua (revision 0) +++ nmap.standalone.lua (working copy) @@ -0,0 +1,733 @@ +--- +-- Fake nmap module. Designed for running stuff stand-alone +-- within a separate Lua environment. All nmap related stuff +-- has been either removed or replaced with Pure Lua-based equivs. +-- +-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html + +require 'base' +local print = print +local clock = os.clock + +module 'nmap' + +registry = {} +registry.args = {} + +--- Returns the debugging level as a non-negative integer. +-- +-- The debugging level can be set with the -d option. +-- @return The debugging level. +-- @usage if nmap.debugging() > 0 then ... end +function debugging() return 9 end + +--- Determines whether Nmap was compiled with SSL support. +-- +-- This can be used to avoid sending SSL probes when SSL is not available. +-- @return True if Nmap was compiled with SSL support, false otherwise. +function have_ssl() return true end + +--- Returns the verbosity level as a non-negative integer. +-- +-- The verbosity level can be set with the -v option. When +-- a script is given by name with the --script option, as +-- opposed to being selected by default or by category, its verbosity +-- level is automatically increased by one. +-- @return The verbosity level. +-- @usage if nmap.verbosity() > 0 then ... end +function verbosity() return 9 end + +--- Returns whether a script should be able to perform privileged operations +-- +-- @return True if Nmap is running privileged, false otherwise. +function is_privileged() return true end + +--- Resolves the specified host name using the optional address family and +-- returns a table containing all of the matching addresses. +-- +-- If no address family is given, resolve() will return all addresses for the +-- name. +-- +-- @param host Host name to resolve +-- @param family Address family string (such as "inet") to specify the type +-- of addresses returned +-- @see address_family +-- @return Status (true or false) +-- @return Table containing addresses resolved from the host name if status +-- is true, or an error string if status is false +-- @usage local status, t = nmap.resolve("www.kame.net", nmap.address_family()) +function resolve(host, family) print "ERROR: Unimplemented!" end + +--- Returns the address family Nmap is using. +-- +-- For example, if Nmap is run with the -6 option, then "inet6" is returned. +-- +-- @return The address family as a string ("inet" or "inet6") +-- @usage local family = nmap.address_family() +function address_family() return 'inet' end + +--- Searches for the specified file and returns a string containing its path if +-- it is found and readable (to the process). +-- +-- If the file is not found, not readable, or is a directory, nil +-- is returned. +-- @usage +-- nmap.fetchfile("nmap-rpc") --> "/usr/local/share/nmap/nmap-rpc" +-- @param filename Filename to search for. +-- @return String representing the full path to the file or nil. +function fetchfile(filename) print "ERROR: Unimplemented!" end + +--- Returns the timing level as a non-negative integer. +-- +-- Possible return values vary from 0 to 5, +-- corresponding to the six built-in Nmap timing templates. The timing level +-- can be set with the -T option. +-- @return The timing level. +function timing_level() return 4 end + +--- Gets a port table for a port on a given host. +-- +-- This function takes a host table and a port table and returns a port table +-- for the queried port. The port table returned is similar in structure to the +-- ones passed to the hostrule, portrule, and +-- action functions. If the given port was not scanned the function +-- returns nil. +-- +-- You can of course reuse the host and port tables passed to a script's rule +-- function. The purpose of this call is to be able to match scripts against +-- more than one open port. For example if the target host has an open port 22 +-- and a running identd server, then you can write a script which will only fire +-- if both ports are open and there is an identification server on port 113. +-- While it is possible to specify IP addresses different to the currently +-- scanned target, the result will only be correct if the target is in the +-- currently scanned group of hosts. +-- @param host Host table, containing an ip field. +-- @param port Port table, containing number and +-- protocol fields. +-- @return A new port table holding the status and information for the port, or nil. +-- @usage p = nmap.get_port_state({ip="127.0.0.1"}, {number="80", protocol="tcp"}) +function get_port_state(host, port) print "ERROR: Unimplemented!" end + +--- Iterates over port tables matching protocol and state for a given host +-- +-- This function takes a host table, previous port table, port protocol and +-- port state to return matching port tables on a host. +-- +-- The first time you call this function, pass nil for the port +-- parameter to get the first matching port table. From then on, pass the +-- previous port table returned by this function to the port parameter for the +-- next matching port table. +-- +-- @param host Host table, containing an ip field +-- @param port Port table, containing a number field; or nil +-- for first port +-- @param proto Port protocol, such as "tcp" +-- @param state Port state, such as "open" +-- @return Next port table for host, or nil when exhausted +-- @usage port = nmap.get_ports(host, port, "tcp", "open") +function get_ports(host, port, proto, state) print "ERROR: Unimplemented!" end + +--- Sets the state of a port on a given host. +-- +-- Using this function, the final port state, reflected in Nmap's results, can +-- be changed for a target. This is useful when Nmap detects a port as +-- open|filtered, but the script successfully connects to that +-- port. In this case, the script can set the port state to open. +-- This function doesn't change the original port table passed a script's +-- action function. +-- @param host Host table, containing an ip field. +-- @param port Port table, containing number and +-- protocol fields. +-- @param state Port state, like "open" or "closed". +function set_port_state(host, port, state) end + +--- Sets version information on a port. +-- +-- NSE scripts are sometimes able to determine the service name and application +-- version listening on a port. A whole script category (version) +-- was designed for this purpose. This function is used to record version +-- information when it is discovered. +-- +-- The host and port arguments to this function should either be the tables +-- passed to the action method or they should have the same structure. The port +-- argument specifies the port to operate on through its number +-- and protocol fields. and also contains the new version +-- information to set. The version detection fields this function looks at are +-- name, product, version, +-- extrainfo, hostname, ostype, +-- devicetype, and service_tunnel. All these keys are +-- optional. +-- +-- The probestate argument describes the state in which the script +-- completed. It is a string, one of: "hardmatched", +-- "softmatched", "nomatch", +-- "tcpwrapped", or "incomplete". +-- "hardmatched" is almost always used (and is the default), +-- as it signifies a +-- successful match. The other possible states are generally only used for +-- standard version detection rather than the NSE enhancement. +-- @param host Host table, containing an ip field. +-- @param port Port table, containing number and +-- protocol fields, as well as any additional version information +-- fields. +-- @param probestate The state of the probe: "hardmatched", +-- "softmatched", "nomatch", +-- "tcpwrapped", or "incomplete". +function set_port_version(host, port, probestate) end + +--- Returns the current date and time in seconds. +-- @return The number of seconds since the epoch (on most systems this is +-- 01/01/1970) as a floating point value. +-- @usage local now = nmap.clock() +clock = clock + +--- Returns the current date and time in milliseconds. +-- @return The number of milliseconds since the epoch (on most systems this is +-- 01/01/1970). +-- @usage local now = nmap.clock_ms() +function clock_ms() return clock() * 1000 end + +--- Gets the link-level hardware type of an interface. +-- +-- This function takes a dnet-style interface name and returns a string +-- representing the hardware type of the interface. Possible return values are +-- "ethernet", "loopback", "p2p", or +-- nil if none of the other types apply. +-- @param interface_name The name of the interface. +-- @return "ethernet", "loopback", +-- "p2p", or nil. +-- @usage iface_type = nmap.get_interface_link("eth0") +function get_interface_link(interface_name) return "ethernet" end + +--- Create a mutex on an object. +-- +-- This function returns another function that works as a mutex on the object +-- passed. This object can be any Lua data type except nil, +-- Booleans, and Numbers. The Mutex (the returned function) allows you to lock, +-- try to lock, and release the mutex. The Mutex function takes only one +-- argument, which must be one of +-- * "lock": makes a blocking lock on the mutex. If the mutex is busy then the thread will yield and wait. The function returns with the mutex locked. +-- * "trylock": makes a non-blocking lock on the mutex. If the mutex is busy then it immediately returns a false value. Otherwise, the mutex locks the mutex and returns true. +-- * "done": releases the mutex and allows another thread to lock it. If the thread does not have a lock on the mutex, an error will be raised. +-- * "running": returns the thread locked on the mutex or nil if no thread is locked. This should only be used for debugging as it interferes with finished threads from being collected. +-- +-- NSE maintains a weak reference to the Mutex function so other calls to +-- nmap.mutex with the same object will return the same function (Mutex); +-- however, if you discard your reference to the Mutex then it may be collected +-- and subsequent calls to nmap.mutex with the object will return a different +-- Mutex! +-- @param object Object to create a mutex for. +-- @return Mutex function which takes one of the following arguments: +-- "lock", "trylock", "done", or +-- "running". +-- @usage +-- id = "My Script's Unique ID" +-- +-- local mutex = nmap.mutex(id) +-- function action(host, port) +-- mutex "lock" +-- -- do stuff +-- mutex "done" +-- return script_output +-- end +function mutex(object) print "ERROR: Unimplemented!" end + +--- Create a condition variable for an object. +-- +-- This function returns a function that works as a Condition Variable for the +-- given object parameter. The object can be any Lua data type except +-- nil, Booleans, and Numbers. The Condition Variable (returned +-- function) allows you wait, signal, and broadcast on the condition variable. +-- The Condition Variable function takes only one argument, which must be one of +-- * "wait": Wait on the condition variable until another thread wakes us. +-- * "signal": Wake up a single thread from the waiting set of threads for this condition variable. +-- * "broadcast": Wake up all threads in the waiting set of threads for this condition variable. +-- +-- NSE maintains a weak reference to the Condition Variable so other calls to +-- nmap.condvar with the same object will return the same function (Condition +-- Variable); however, if you discard your reference to the Condition +-- Variable then it may be collected; and, subsequent calls to nmap.condvar with +-- the object will return a different Condition Variable function! +-- +-- In NSE, Condition Variables are typically used to coordinate with threads +-- created using the stdnse.new_thread facility. The worker threads must +-- wait until work is available that the master thread (the actual running +-- script) will provide. Once work is created, the master thread will awaken +-- one or more workers so that the work can be done. +-- +-- It is important to check the predicate (the test to see if your worker +-- thread should "wait" or not) BEFORE and AFTER the call to wait. You are +-- not guaranteed spurious wakeups will not occur (that is, there is no +-- guarantee your thread will not be awakened when no thread called +-- "signal" or "broadcast" on the condition variable). +-- One important check for your worker threads, before and after waiting, +-- should be to check that the master script thread is still alive. +-- (To check that the master script thread is alive, obtain the "base" thread +-- using stdnse.base and use coroutine.status). You do not want your worker +-- threads to continue when the script has ended for reasons unknown to your +-- worker thread. You are guaranteed that all threads waiting on a +-- condition variable will be awakened if any thread that has accessed +-- the condition variable via nmap.condvar ends for any +-- reason. This is essential to prevent deadlock with threads +-- waiting for another thread to awaken +-- them that has ended unexpectedly. +-- @see stdnse.new_thread +-- @see stdnse.base +-- @param object Object to create a condition variable for. +-- @return ConditionVariable Condition variable function. +-- @usage +-- local myobject = {} +-- local cv = nmap.condvar(myobject) +-- cv "wait" -- waits until another thread calls cv "signal" +function condvar(object) print "ERROR: Unimplemented!" end + +--- Creates a new exception handler. +-- +-- This function returns an exception handler function. The exception handler is +-- meant to be wrapped around other function calls that may raise an exception. +-- A function raises an exception by making its first return value false and its +-- second return value a message describing the error. When an exception occurs, +-- the exception handler optionally calls a user-provided cleanup function, then +-- terminates the script. When an exception does not occur (the wrapped +-- function's first return value is true), the exception handler strips off the +-- first return value and returns the rest. +-- +-- The optional cleanup function is passed as the sole argument to +-- new_try. It can be used to release sockets or other resources +-- before the script terminates. +-- +-- A function that may raise an exception must follow the return protocol +-- understood by this function: on an exception its return values are +-- false or nil followed by an error message; on +-- success its return values are any true value followed by any other results. +-- @param handler User cleanup function (optional). +-- @usage +-- local result, socket, try, catch +-- +-- result = "" +-- socket = nmap.new_socket() +-- catch = function() +-- socket:close() +-- end +-- try = nmap.new_try(catch) +-- try(socket:connect(host, port)) +-- result = try(socket:receive_lines(1)) +-- try(socket:send(result)) +function new_try(handler) print "ERROR: Unimplemented!" end + +--- Returns a new NSE socket object. +-- +-- To allow for efficient and parallelizable network I/O, NSE provides an +-- interface to Nsock, the Nmap socket library. The smart callback mechanism +-- Nsock uses is fully transparent to NSE scripts. The main benefit of NSE's +-- sockets is that they never block on I/O operations, allowing many scripts to +-- be run in parallel. The I/O parallelism is fully transparent to authors of +-- NSE scripts. In NSE you can either program as if you were using a single +-- non-blocking socket or you can program as if your connection is blocking. +-- Seemingly blocking I/O calls still return once a specified timeout has been +-- exceeded. +-- +-- NSE sockets are the recommended way to do network I/O. They support +-- connect-style sending and receiving over TCP and UDP (and SSL), +-- as well as raw socket receiving. +-- @param protocol a protocol string (optional, defaults to "tcp"). +-- @param af an address family string (optional, defaults to "inet"). +-- @return A new NSE socket. +-- @see pcap_open +-- @usage local socket = nmap.new_socket() +function new_socket(protocol, af) print "ERROR: Unimplemented!" end + +--- Sets the local address of a socket. +-- +-- This socket method sets the local address and port of a socket. It must be +-- called before connect. The address set by bind +-- overrides Nmap's source address and port set by the -S and +-- -g options. +-- @param addr Address string or nil (optional). +-- @param port Port number or nil (optional). +-- @return Status (true or false). +-- @return Error string (if status is false). +-- @usage +-- try = nmap.new_try() +-- try(socket:bind(nil, 53)) +-- try(socket:bind("1.2.3.4")) +-- try(socket:bind("2001:db8::1")) +-- try(socket:bind("1.2.3.4", 53)) +function bind(addr, port) print "ERROR: Unimplemented!" end + +--- Establishes a connection. +-- +-- This method puts a socket in a state ready for communication. It takes as +-- arguments a host descriptor (a host table, IP address, or hostname), a port +-- descriptor (a port table or number), and optionally a protocol. If given, the +-- protocol must be one of "tcp", "udp" or +-- "ssl". The default value for the protocol is +-- port.protocol if port is a port table, otherwise +-- "tcp". +-- +-- If host is a host table, it must contain at least one of the +-- keys addr or targetname. If targetname +-- is given, it is used to request the correct certificate in SSL connections. +-- Passing a string instead of a host table acts like host.addr and +-- host.targetname were set to the same value. If port +-- is a table, it must contain the number key. +-- +-- On success the function returns a true value. On failure it returns a false +-- value (false or nil) and an error string. Those +-- strings are taken from the gai_strerror C function. They are +-- (with the error code in parentheses): +-- * "Address family for hostname not supported" (EAI_ADDRFAMILY) +-- * "Temporary failure in name resolution" (EAI_AGAIN) +-- * "Bad value for ai_flags" (EAI_BADFLAGS) +-- * "Non-recoverable failure in name resolution" (EAI_FAIL) +-- * "ai_family not supported" (EAI_FAMILY) +-- * "Memory allocation failure" (EAI_MEMORY) +-- * "No address associated with hostname" (EAI_NODATA) +-- * "Name or service not known" (EAI_NONAME) +-- * "Servname not supported for ai_socktype" (EAI_SERVICE) +-- * "ai_socktype not supported" (EAI_SOCKTYPE) +-- * "System error" (EAI_SYSTEM) +-- In addition to these standard system error messages there are two +-- NSE-specific errors: +-- * "Sorry, you don't have OpenSSL": The protocol is "ssl" but Nmap was compiled without OpenSSL support. +-- * "invalid connection method": The second parameter is not one of "tcp", "udp", and "ssl". +-- @param host Host table, hostname or IP address. +-- @param port Port table or number. +-- @param protocol "tcp", "udp", or +-- "ssl" (default "tcp", or whatever was set in +-- new_socket). +-- @return Status (true or false). +-- @return Error code (if status is false). +-- @see new_socket +-- @usage +-- local status, err = socket:connect(host, port) +-- if not status then +-- return string.format("Can't connect: %s", err) +-- end +function connect(host, port, protocol) print "ERROR: Unimplemented!" end + +--- Reconnect the open (connected) socket with SSL. +-- +-- It is sometimes desirable to request SSL over an established connection. +-- The internal buffers for the socket are cleared when the reconnection is +-- made. Any received data that has not yet been read through a call to receive +-- is lost. +-- @usage +-- local status, err = socket:reconnect_ssl() +-- if not status then +-- return string.format("Can't reconnect with ssl: %s", err) +-- end +function reconnect_ssl() print "ERROR: Unimplemented!" end + +--- Sends data on an open socket. +-- +-- This socket method sends the data contained in the data string through an +-- open connection. On success the function returns a true value. If the send +-- operation fails, the function returns a false value (false or +-- nil) along with an error string. The error strings are +-- * "Trying to send through a closed socket": There was no call to socket:connect before the send operation. +-- * "TIMEOUT": The operation took longer than the specified timeout for the socket. +-- * "ERROR": An error occurred inside the underlying Nsock library. +-- * "CANCELLED": The operation was cancelled. +-- * "KILL": For example the script scan is aborted due to a faulty script. +-- * "EOF": An EOF was read (probably will not occur for a send operation). +-- @param data The data to send. +-- @return Status (true or false). +-- @return Error code (if status is false). +-- @see new_socket +-- @usage local status, err = socket:send(data) +function send(data) print "ERROR: Unimplemented!" end + +--- Sends data on an unconnected socket to a given destination. +-- +-- Sockets that have not been connected do not have an implicit +-- destination address, so the send function doesn't work. Instead +-- the destination must be given with each send using this function. The +-- protocol and address family of the socket must have been set in +-- new_socket. On +-- success the function returns a true value. If the send operation fails, the +-- function returns a false value (false or nil) along +-- with an error string. The error strings are +-- * "Trying to send through a closed socket": There was no call to socket:connect before the send operation. +-- * "TIMEOUT": The operation took longer than the specified timeout for the socket. +-- * "ERROR": An error occurred inside the underlying Nsock library. +-- * "CANCELLED": The operation was cancelled. +-- * "KILL": For example the script scan is aborted due to a faulty script. +-- * "EOF": An EOF was read (probably will not occur for a send operation). +-- @param host The hostname or IP address to send to. +-- @param port The port number to send to. +-- @param data The data to send. +-- @return Status (true or false). +-- @return Error code (if status is false). +-- @usage local status, err = socket:send(data) +function sendto(host, port, data) print "ERROR: Unimplemented!" end + +--- Receives data from an open socket. +-- +-- The receive method does a non-blocking receive operation on an open socket. +-- On success the function returns true along with the received data. On +-- failure the function returns a false value (false or +-- nil) along with an error string. A failure occurs for example if +-- receive is called on a closed socket. The receive call returns +-- to the NSE script all the data currently stored in the receive buffer of the +-- socket. Error conditions are the same as for send. +-- @return Status (true or false). +-- @return Data (if status is true) or error string (if status is false). +-- @see new_socket +-- @usage local status, data = socket:receive() +function receive() print "ERROR: Unimplemented!" end + +--- Receives lines from an open connection. +-- +-- Tries to receive at least n lines from an open connection. A +-- line is a string delimited with \n characters. If no data was +-- was received before the operation times out a "TIMEOUT" error +-- occurs. If even one character was received then it is returned with success. +-- On the other hand, if more than n lines were received, all are +-- returned, not just n. Use stdnse.make_buffer to +-- guarantee only one line is returned per call. +-- +-- The return values and error codes are the same as for send. +-- @param n Minimum number of lines to read. +-- @return Status (true or false). +-- @return Data (if status is true) or error string (if status is false). +-- @see new_socket +-- @usage local status, lines = socket:receive_lines(1) +function receive_lines(n) print "ERROR: Unimplemented!" end + +--- Receives bytes from an open connection. +-- +-- Tries to receive at least n bytes from an open connection. Like +-- in receive_lines, n is the minimum amount of +-- characters we would like to receive. If more arrive, we get all of them. If +-- even one is received then it is returned. If no characters arrive before the +-- operation times out, a "TIMEOUT" error occurs. +-- +-- The return values and error codes are the same as for send. +-- @param n Minimum number of bytes to read. +-- @return Status (true or false). +-- @return Data (if status is true) or error string (if status is false). +-- @see new_socket +-- @usage local status, bytes = socket:receive_bytes(1) +function receive_bytes(n) print "ERROR: Unimplemented!" end + +--- Reads from a socket using a buffer and an arbitrary delimiter. +-- +-- This method reads data from the network until it encounters the given +-- delimiter string (or matches the function passed in). This function +-- continues to read from the network until the delimiter is found or the +-- function times out. If data is read beyond the delimiter, that data is +-- saved in a buffer for the next call to receive_buf. +-- +-- The first argument may be either a pattern or a function. If a pattern, that +-- pattern is used to separate the data. If a function, it must take exactly +-- one parameter (the buffer) and its return values must be in the same format +-- as those of string.find (offsets to the start and the end of +-- the delimiter inside the buffer, or nil if the delimiter is not +-- found). The nselib match.lua module provides functions for +-- matching against regular expressions or byte counts. These functions are +-- suitable as arguments to receive_buf. +-- +-- The second argument to receive_buf is a Boolean value +-- controlling whether the delimiting string is returned along with the +-- received data (true) or discarded (false). +-- +-- On success the function returns true along with the received data. On failure +-- the function returns false or nil along with an +-- receive error string. This function may also throw errors for incorrect usage. +-- @param delimiter A Lua pattern or a function with return values like those of +-- string.find. +-- @param keeppattern Whether to return the delimiter string with any returned +-- data. +-- @return Status (true or false). +-- @return Data (if status is true) or error string (if status is false). +-- @see new_socket +-- @usage local status, line = socket:receive_buf("\r?\n", false) +function receive_buf(delimiter, keeppattern) print "ERROR: Unimplemented!" end + +--- Closes an open connection. +-- +-- On success the function returns true. If the close fails, the function +-- returns false or nil and an error string. Currently +-- the only error message is "Trying to close a closed socket", +-- which is issued if the socket has already been closed. +-- +-- Sockets are subject to garbage collection. Should you forget to close a +-- socket, it will get closed before it gets deleted (on the next occasion Lua's +-- garbage collector is run). However since garbage collection cycles are +-- difficult to predict, it is considered good practice to close opened sockets. +-- @return Status (true or false). +-- @return Error code (if status is false). +-- @see new_socket +-- @usage socket:close() +function close() end + +--- Gets information about a socket. +-- +-- This function returns information about a socket object. It returns five +-- values. If an error occurred, the first value is false or +-- nil and the second value is an error string. Otherwise the first +-- value is true and the remaining 4 values describe both endpoints of the TCP +-- connection. If you put the call inside an exception handler created by +-- new_try the status value is consumed. The call can be used for +-- example if you want to query an authentication server. +-- @return Status (true or false). +-- @return Local IP address (if status is true) or error string (if status is +-- false). +-- @return Local port number (if status is true). +-- @return Remote IP address (if status is true). +-- @return Remote port number (if status is true). +-- @see new_socket +-- @usage local status, lhost, lport, rhost, rport = socket:get_info() +function get_info() print "ERROR: Unimplemented!" end + +--- Sets a timeout for socket input and output operations. +-- +-- After this time, given in milliseconds, socket operations will time out and +-- return. The default value is 30,000 (30 seconds). The lowest allowed value is +-- 10 ms, since this is the granularity of NSE network I/O. +-- @param t Timeout in milliseconds. +-- @see new_socket +-- @usage socket:set_timeout(10000) +function set_timeout(t) end + +--- Opens a socket for raw packet capture. +-- +-- @param device The dnet-style interface name of the device you want to capture +-- from. +-- @param snaplen The length of each packet you want to capture (similar to the +-- -s option to tcpdump) +-- @param promisc Boolean value for whether the interface should activate +-- promiscuous mode. +-- @param bpf A string describing a Berkeley Packet Filter expression (like +-- those provided to tcpdump). +-- @see new_socket, pcap_receive +-- @usage +-- local socket = nmap.new_socket() +-- socket:pcap_open("eth0", 64, false, "tcp") +function pcap_open(device, snaplen, promisc, bpf) print "ERROR: Unimplemented!" end + +--- Receives a captured packet. +-- +-- If an error or timeout occurs, the function returns false and an error +-- message. Otherwise, the function returns true followed by the packet length, +-- layer two header, layer three header and packet capture time. +-- @return Status (true or false). +-- @return The length of the captured packet (this may be smaller than the +-- actual packet length since packets are truncated when the +-- libpcap snaplen parameter is smaller than the total packet length). +-- @return Data from the second OSI layer (e.g. ethernet headers). +-- @return Data from the third OSI layer (e.g. IPv4 headers). +-- @return Packet capture time, as floating point seconds since the epoch +-- @see pcap_open +-- @usage status, plen, l2_data, l3_data, time = socket:pcap_receive() +function pcap_receive() print "ERROR: Unimplemented!" end + +--- Closes a pcap device. +-- @see close, pcap_close +-- @usage socket:pcap_close() +function pcap_close() print "ERROR: Unimplemented!" end + +--- +-- Retrieves the SSL certificate of the peer. The returned value can be accessed +-- like a table and has the following members: +-- +-- +-- subject = { commonName = "...", countryName = "...", +-- { "2", "5", "4", "15" } = "...", ... }, +-- issuer = { commonName = "...", ... }, +-- pubkey = { type = "rsa", bits = 1024 }, +-- validity = { notBefore = { year = 2020, month = 5, day = 5, +-- hour = 0, min = 0, sec = 0 }, +-- notAfter = { year = 2021, month = 5, day = 5, +-- hour = 0, min = 0, sec = 0 } }, +-- pem = "-----BEGIN CERTIFICATE-----\nMIIFxzCCBK+gAwIBAgIQX02QuADDB7CVj..." +-- +-- +-- It also has the following member functions: +-- +-- * digest(algorithm) returns the digest of the certificate using the given digest algorithm, which is any of the strings returned by openssl.supported_digests, typicaly something like "md5" or "sha1". +-- +-- The "subject" and "issuer" fields hold each +-- distinguished name. Fields with an unknown OID are represented as an array +-- whose elements are the numeric components of the OID, encoded as strings. +-- +-- The "validity" table has the members "notBefore" +-- and "notAfter". Each of these is a table as returned by +-- os.date("!*t") if the date in the certificate could be parsed, +-- except that they lack the "wday" and "yday" +-- members. If the date could not be parsed, the value will be a string +-- containing the raw byte values of the field. If absent, the value will be +-- nil. +-- +-- The "pem" field contains a PEM-encoded string of the entire +-- contents of the certificate. +-- @return A table as described above. +-- @usage +-- local s = nmap.new_socket() +-- local status, error = s:connect(host, port, "ssl") +-- if status then +-- local cert = s:get_ssl_certificate() +-- local digest = cert:digest("md5") +-- end +function get_ssl_certificate() print "ERROR: Unimplemented!" end + +--- Creates a new dnet object, used to send raw packets. +-- @usage local dnet = nmap.new_dnet() +function new_dnet() print "ERROR: Unimplemented!" end + +--- Opens an ethernet interface for raw packet sending. +-- +-- An error ("device is not valid ethernet interface") is thrown +-- in case the provided argument is not valid. +-- @param interface_name The dnet-style name of the interface to open. +-- @see new_dnet +-- @usage dnet:ethernet_open("eth0") +function ethernet_open(interface_name) print "ERROR: Unimplemented!" end + +--- Sends a raw ethernet frame. +-- +-- The dnet object must be associated with a previously opened interface. The +-- packet must include the IP and ethernet headers. If there was no previous +-- valid call to ethernet_open an error is thrown +-- ("dnet is not valid opened ethernet interface"). +-- @param packet An ethernet frame to send. +-- @see new_dnet +-- @usage dnet:ethernet_send(packet) +function ethernet_send(packet) print "ERROR: Unimplemented!" end + +--- Closes an ethernet interface. +-- +-- An error ("device is not valid ethernet interface") is thrown +-- in case the provided argument is not valid. +-- @see new_dnet, ethernet_open +-- @usage dnet:ethernet_close() +function ethernet_close() end + +--- Opens a socket for raw IPv4 packet sending. +-- @see new_dnet +-- @usage dnet:ip_open() +function ip_open() print "ERROR: Unimplemented!" end + +--- Sends a raw IPv4 packet. +-- +-- The dnet object must be associated with a previously opened socket. The +-- packet must begin with an IP header. If there was no previous valid call +-- to ip_open an error is thrown. +-- @param packet An IP packet to send. +-- @see new_dnet +-- @usage dnet:ip_send(packet) +function ip_send(packet) print "ERROR: Unimplemented!" end + +--- Closes a raw IPv4 socket. +-- @see new_dnet, ip_open +-- @usage dnet:ip_close() +function ip_close() print "ERROR: Unimplemented!" end + +--- Writes to a log file. +-- +-- Writes string to file ("stdout" or "stderr"). +-- Use stdnse.print_debug to print debug information based on the +-- debugging level. +-- @see stdnse.print_debug +function log_write(file, string) print(string) end Index: stdnse.lua =================================================================== --- stdnse.lua (revision 29646) +++ stdnse.lua (working copy) @@ -55,9 +55,9 @@ _ENV.sleep = nmap.socket.sleep; --- --- Prints a formatted debug message if the current debugging level is greater +-- Prints a formatted debug message if the current verbosity level is greater -- than or equal to a given level. --- +-- -- This is a convenience wrapper around -- nmap.log_write. The first optional numeric -- argument, level, is used as the debugging level necessary @@ -75,30 +75,8 @@ end end ---- --- Prints a formatted verbosity message if the current verbosity level is greater --- than or equal to a given level. --- --- This is a convenience wrapper around --- nmap.log_write. The first optional numeric --- argument, level, is used as the verbosity level necessary --- to print the message (it defaults to 1 if omitted). All remaining arguments --- are processed with Lua's string.format function. --- @param level Optional verbosity level. --- @param fmt Format string. --- @param ... Arguments to format. -print_verbose = function(level, fmt, ...) - local l, d = tonumber(level), nmap.verbosity(); - if l and l <= d then - nmap.log_write("stdout", format(fmt, ...)); - elseif not l and 1 <= d then - nmap.log_write("stdout", format(level, fmt, ...)); - end -end - - --- Join a list of strings with a separator string. --- +-- -- This is Lua's table.concat function with the parameters -- swapped for coherence. -- @usage @@ -109,7 +87,7 @@ -- @return Concatenated string. function strjoin(delimiter, list) assert(type(delimiter) == "string" or type(delimiter) == nil, "delimiter is of the wrong type! (did you get the parameters backward?)") - + return concat(list, delimiter); end @@ -164,7 +142,7 @@ --- Return a wrapper closure around a socket that buffers socket reads into -- chunks separated by a pattern. --- +-- -- This function operates on a socket attempting to read data. It separates the -- data by sep and, for each invocation, returns a piece of the -- separated data. Typically this is used to iterate over the lines of data @@ -271,7 +249,7 @@ -- @param s String or number to be encoded. -- @param options Table specifiying formatting options. -- @return String in hexadecimal format. -function tohex( s, options ) +function tohex( s, options ) options = options or EMPTY local separator = options.separator local hex @@ -453,7 +431,7 @@ return nmap.clock() * 1000000 end ----Get the indentation symbols at a given level. +---Get the indentation symbols at a given level. local function format_get_indent(indent, at_end) local str = "" local had_continue = false @@ -505,9 +483,9 @@ -- Used to put 'ERROR: ' in front of all lines on error messages local prefix = "" -- Initialize the output string to blank (or, if we're at the top, add a newline) - local output = {} + local output = "" if(not(indent)) then - insert(output, '\n') + output = '\n' end if(not(status)) then @@ -527,18 +505,12 @@ if(data['name']) then if(data['warning'] and nmap.debugging() > 0) then - insert(output, format("%s%s%s (WARNING: %s)\n", - format_get_indent(indent), prefix, - data['name'], data['warning'])) + output = output .. format("%s%s%s (WARNING: %s)\n", format_get_indent(indent), prefix, data['name'], data['warning']) else - insert(output, format("%s%s%s\n", - format_get_indent(indent), prefix, - data['name'])) + output = output .. format("%s%s%s\n", format_get_indent(indent), prefix, data['name']) end elseif(data['warning'] and nmap.debugging() > 0) then - insert(output, format("%s%s(WARNING: %s)\n", - format_get_indent(indent), prefix, - data['warning'])) + output = output .. format("%s%s(WARNING: %s)\n", format_get_indent(indent), prefix, data['warning']) end for i, value in ipairs(data) do @@ -555,46 +527,44 @@ insert(new_indent, true) end - insert(output, format_output_sub(status, value, new_indent)) - + output = output .. format_output_sub(status, value, new_indent) + elseif(type(value) == 'string') then local lines = splitlines(value) for j, line in ipairs(lines) do - insert(output, format("%s %s%s\n", - format_get_indent(indent, i == #data and j == #lines), - prefix, line)) + output = output .. format_get_indent(indent, i == #data and j == #lines) .. " " .. prefix .. line .. "\n" end end end - return concat(output) + return output end ----Takes a table of output on the commandline and formats it for display to the --- user. This is basically done by converting an array of nested tables into a --- string. In addition to numbered array elements, each table can have a 'name' --- and a 'warning' value. The 'name' will be displayed above the table, and +---Takes a table of output on the commandline and formats it for display to the +-- user. This is basically done by converting an array of nested tables into a +-- string. In addition to numbered array elements, each table can have a 'name' +-- and a 'warning' value. The 'name' will be displayed above the table, and -- 'warning' will be displayed, with a 'WARNING' tag, if and only if debugging --- is enabled. --- +-- is enabled. +-- -- Here's an example of a table: -- -- local domains = {} -- domains['name'] = "DOMAINS" -- table.insert(domains, 'Domain 1') -- table.insert(domains, 'Domain 2') --- +-- -- local names = {} -- names['name'] = "NAMES" -- names['warning'] = "Not all names could be determined!" -- table.insert(names, "Name 1") --- +-- -- local response = {} -- table.insert(response, "Apple pie") -- table.insert(response, domains) -- table.insert(response, names) --- +-- -- return stdnse.format_output(true, response) -- -- @@ -610,13 +580,13 @@ -- |_ Name 1 -- -- ---@param status A boolean value dictating whether or not the script succeeded. +--@param status A boolean value dictating whether or not the script succeeded. -- If status is false, and debugging is enabled, 'ERROR' is prepended --- to every line. If status is false and debugging is disabled, no output --- occurs. ---@param data The table of output. +-- to every line. If status is false and ebugging is disabled, no output +-- occurs. +--@param data The table of output. --@param indent Used for indentation on recursive calls; should generally be set to --- nil when callling from a script. +-- nil when callling from a script. -- @return nil, if data is empty, otherwise a -- multiline string. function format_output(status, data, indent) @@ -644,16 +614,7 @@ local function arg_value(argname) if nmap.registry.args[argname] then return nmap.registry.args[argname] - else - -- if scriptname.arg is not there, check "arg" - local argument_frags = strsplit("%.", argname) - if #argument_frags > 0 then - if nmap.registry.args[argument_frags[2]] then - return nmap.registry.args[argument_frags[2]] - end - end end - for _, v in ipairs(nmap.registry.args) do if v == argname then return 1 @@ -686,7 +647,7 @@ function get_script_args (...) local args = {} - for i, set in ipairs({...}) do + for i, set in ipairs({...}) do if type(set) == "string" then set = {set} end @@ -702,10 +663,10 @@ return unpack(args, 1, select("#", ...)) end ----Get the best possible hostname for the given host. This can be the target as given on --- the commandline, the reverse dns name, or simply the ip address. ---@param host The host table (or a string that'll simply be returned). ---@return The best possible hostname, as a string. +---Get the best possible hostname for the given host. This can be the target as given on +-- the commandline, the reverse dns name, or simply the ip address. +--@param host The host table (or a string that'll simply be returned). +--@return The best possible hostname, as a string. function get_hostname(host) if type(host) == "table" then return host.targetname or ( host.name ~= '' and host.name ) or host.ip @@ -715,7 +676,7 @@ end ---Retrieve an item from the registry, checking if each sub-key exists. If any key doesn't --- exist, return nil. +-- exist, return nil. function registry_get(subkeys) local registry = nmap.registry local i = 1 @@ -733,7 +694,7 @@ return registry end ---Check if the given element exists in the registry. If 'key' is nil, it isn't checked. +--Check if the given element exists in the registry. If 'key' is nil, it isn't checked. function registry_exists(subkeys, key, value) local subkey = registry_get(subkeys) @@ -750,12 +711,12 @@ return false end ----Add an item to an array in the registry, creating all sub-keys if necessary. +---Add an item to an array in the registry, creating all sub-keys if necessary. -- For example, calling: -- registry_add_array({'192.168.1.100', 'www', '80', 'pages'}, 'index.html') -- Will create nmap.registry['192.168.1.100'] as a table, if necessary, then add a table -- under the 'www' key, and so on. 'pages', finally, is treated as an array and the value --- given is added to the end. +-- given is added to the end. function registry_add_array(subkeys, value, allow_duplicates) local registry = nmap.registry local i = 1 @@ -785,8 +746,8 @@ end ---Similar to registry_add_array, except instead of adding a value to the --- end of an array, it adds a key:value pair to the table. -function registry_add_table(subkeys, key, value, allow_duplicates) +-- end of an array, it adds a key:value pair to the table. +function registry_add_table(subkeys, key, value) local registry = nmap.registry local i = 1