1
0
mirror of https://github.com/nmap/nmap.git synced 2026-01-25 07:39:02 +00:00

Document the socket, pcap, and dnet functions in nselib/nmap.luadoc.

This commit is contained in:
david
2008-10-16 20:33:23 +00:00
parent 3415425322
commit 3ff15bf16d
2 changed files with 299 additions and 469 deletions

View File

@@ -1103,337 +1103,10 @@ action refer to <xref linkend="nse-tutorial-action"/>.
classical network uses: Users create a socket, connect it to a
remote address, send and receive data and close the socket again.
Everything up to the Transport layer (which is either TCP, UDP or
SSL) is handled by the library. The following socket API methods
are supported:
SSL) is handled by the library.
</para>
</sect3>
<para>
<variablelist>
<varlistentry>
<term><option>nmap.new_socket()</option>
</term>
<listitem>
<para>
The <literal>new_socket()</literal> Nmap call returns an
NSE socket object which is the recommended method for network
I/O. It provides facilities to perform communication using the
UDP, TCP and SSL protocol in a uniform manner.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status, error = socket_object:connect(hostid, port, [protocol])</option>
</term>
<listitem>
<para>
The connect method of NSE socket objects will put
the socket in a state ready for communication. It
takes as arguments a host descriptor (either an IP
address or a host name), a port number and optionally
a protocol. The protocol must be one of
<literal>tcp</literal>, <literal>udp</literal> or
<literal>ssl</literal>. By default the connect call
will attempt to open a TCP connection. On success the
returned value of status is
<literal>true</literal>. If the connection attempt has
failed, the error value contains a description of the
error condition stored as a string.
Those strings are
taken from the <function> gai_strerror()</function>
C function. They are (with the errorcode in parentheses):</para>
<itemizedlist>
<listitem>
<para><quote>Address family for hostname not supported</quote> (<literal>EAI_ADDRFAMILY</literal>)</para>
</listitem>
<listitem>
<para><quote>Temporary failure in name resolution</quote> (<literal>EAI_AGAIN</literal>)</para>
</listitem>
<listitem>
<para><quote>Bad value for ai_flags</quote> (<literal>EAI_BADFLAGS</literal>)</para>
</listitem>
<listitem>
<para><quote>Non-recoverable failure in name resolution</quote> (<literal>EAI_FAIL</literal>)</para>
</listitem>
<listitem>
<para><quote>ai_family not supported</quote> (<literal>EAI_FAMILY</literal>)</para>
</listitem>
<listitem>
<para><quote>Memory allocation failure</quote> (<literal>EAI_MEMORY</literal>)</para>
</listitem>
<listitem>
<para><quote>No address associated with hostname</quote> (<literal>EAI_NODATA</literal>)</para>
</listitem>
<listitem>
<para><quote>Name or service not known</quote> (<literal>EAI_NONAME</literal>)</para>
</listitem>
<listitem>
<para><quote>Servname not supported for ai_socktype</quote> (<literal>EAI_SERVICE</literal>)</para>
</listitem>
<listitem>
<para><quote>ai_socktype not supported</quote> (<literal>EAI_SOCKTYPE</literal>)</para>
</listitem>
<listitem>
<para><quote>System error</quote> (<literal>EAI_SYSTEM</literal>)</para>
</listitem>
</itemizedlist>
<para>In addition to these standard system error based messages are the following two NSE-specific errors:</para>
<itemizedlist>
<listitem>
<indexterm><primary>SSL</primary><secondary>in NSE</secondary></indexterm>
<para><quote>Sorry, you don't have OpenSSL.</quote> occurs
if <literal>ssl</literal> is passed as third argument, but Nmap was compiled
without OpenSSL support.</para>
</listitem>
<listitem>
<para><quote>invalid connection method</quote> occurs if
the second parameter is not one of <literal>tcp</literal>, <literal>udp</literal>, <literal>ssl</literal>.</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status, error = socket_object:send(data)</option>
</term>
<listitem>
<para>
The send method sends the data contained in the
<literal>data</literal> string through an open
connection. On success the returned value of status is
<literal>true</literal>. If the send operation
has failed, the error value contains a description of
the error condition stored as a string. The error strings are:
<itemizedlist>
<listitem>
<para><quote>Trying to send through a closed socket</quote>&mdash;if there was no
call to socket_object:connect before the send operation.</para>
</listitem>
<listitem>
<para><quote>TIMEOUT</quote>&mdash;if the operation took longer than the
specified timeout for the socket.</para>
</listitem>
<listitem>
<para><quote>ERROR</quote>&mdash;if an error occurred inside the underlying
Nsock library.</para>
</listitem>
<listitem>
<para><quote>CANCELLED</quote>&mdash;if the operation was cancelled.</para>
</listitem>
<listitem>
<para><quote>KILL</quote>&mdash;if for example the script scan is aborted due
to a faulty script.</para>
</listitem>
<listitem>
<para><quote>EOF</quote>&mdash;if an EOF was read&mdash;will probably not occur
for a send operation.</para>
</listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status, value = socket_object:receive()</option>
</term>
<listitem>
<para>
The receive method does a non-blocking receive operation on
an open socket. On success the returned value of
<literal>status</literal> is
<literal>true</literal> and the received data is stored in
<literal>value</literal>. If receiving data has failed,
<literal>value</literal> contains a description of the error
condition stored as a 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 the send operation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status, value = socket_object:receive_lines(n)</option>
</term>
<listitem>
<para>
Tries to receive at least <replaceable>n</replaceable>
lines from an open connection. A line is a string
delimited with <literal><quote>\n</quote></literal> characters. If
it was not possible to receive at least
<replaceable>n</replaceable> lines before the operation times
out a TIMEOUT error occurs. On the other hand, if more
than <replaceable>n</replaceable> lines were received, all are
returned, not just <replaceable>n</replaceable>. Use
<literal>stdnse.make_buffer</literal> to guarantee one line
is returned per call. On success
the returned value of <replaceable>status</replaceable> is
<literal>true</literal> and the received data is
stored in <replaceable>value</replaceable>. If the connection
attempt has failed, <replaceable>value</replaceable> contains
a description of the error condition stored as string.
Error conditions are the same as for the send operation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status, value = socket_object:receive_bytes(n)</option>
</term>
<listitem>
<para>
Tries to receive at least <replaceable>n</replaceable>
bytes from an open connection. On success the returned
value of <replaceable>status</replaceable> is <literal>true</literal> and the
received data is stored in
<replaceable>value</replaceable>. If operation fails,
<replaceable>value</replaceable> contains a description of the
error condition stored as a string. Similarly to
<literal>receive_lines()</literal>
<replaceable>n</replaceable> is the minimum amount of
characters we would like to receive. If more arrive,
we get all of them. If fewer than <replaceable>n</replaceable> characters arrive
before the operation times out, a TIMEOUT error occurs.
Other error conditions are the same as for the send operation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status, value = socket_object:receive_buf(func/"string", keeppattern)</option>
</term>
<listitem>
<para>
The <literal>receive_buf</literal> method reads data
from the network until it encounters the given delimiter
string (or matches the function passed in). Only data
which occurs before the delimiter is returned, and the
delimiter is then erased. 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 <literal>receive_buf</literal>. This buffer is
cleared on subsequent calls to other Network I/O API
functions.</para>
<para>The <literal>receive_buf</literal> method takes
two arguments. The first one is either a string or
a function. Strings are passed to
Lua's <literal><ulink role="hidepdf"
url="http://www.lua.org/manual/5.1/manual.html#5.4">string.find</ulink></literal>
function as the second (pattern) parameter, with the
buffer data being searched. If the
first <literal>receive_buf</literal> argument is a
function, it is expected to take exactly one
parameter (the buffer) and its return values must be
in the same format as <literal>string.find</literal>
(offsets to the start and the end of the delimiter
inside the buffer, or <literal>nil</literal> if the
delimiter is not found). The nselib
<literal>match.lua</literal> module provides functions
for matching against regular expressions or byte
counts. These functions are suitable as arguments
to <literal>receive_buf</literal>.</para>
<para>The second argument
to <literal>receive_buf</literal> is a Boolean value
which indicates whether the delimiting pattern
should be returned along with the received data or
discarded. The delimiter is included if <literal>true</literal> is passed as the <literal>keeppattern</literal> argument.</para>
<para>The return values of <literal>receive_buf</literal> are the same as the other <literal>receive*</literal> functions. A <literal>(status, val)</literal> tuple is returned. The <literal>status</literal> is <literal>true</literal> if the request was successful. The <literal>val</literal> variable contains the returned data, or an error message if the call failed.</para>
<para>Possible error messages include those described previously for the other
<literal>receive*</literal> functions as well as the
following:
<itemizedlist>
<listitem>
<para><quote>Error inside splitting-function</quote>&mdash;if the first argument was
a function which caused an error while being called.
</para>
</listitem>
<listitem>
<para><quote>Error in <literal>string.find</literal> (<literal>nsockobj:receive_buf</literal>)!</quote>&mdash;if a string
was provided as the first argument, and string.find() yielded an
error while being called.</para>
</listitem>
<listitem>
<para><quote>Expected either a function or a string!</quote>&mdash;if the
first argument was neither a function nor a string.</para>
</listitem>
<listitem>
<para><quote>Delimiter has negative size!</quote>&mdash;if the returned start offset
is greater than the end offset.</para>
</listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status, err = socket_object:close()</option>
</term>
<listitem>
<para>
Closes an open connection. On success the returned value of
<literal>status</literal> is <literal>true</literal>. If the connection
attempt has failed, <literal>value</literal> contains a description
of the error condition stored as a string. Currently the only error
message is: <quote>Trying to close a closed socket</quote>, 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.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status,localip,localport,remoteip,remoteport=socket_object:get_info()</option>
</term>
<listitem>
<para>
This function returns information about the socket
object. It returns 5 values. If an error occurred, the
first value is <literal>nil</literal> and the second
value describes the error condition. Otherwise the
first value describes the success of the operation and
the remaining 4 values describe both endpoints of the
TCP connection. If you put the call in a <literal>try()</literal> statement
the status value is consumed. The call can be used for example if
you want to query an authentication server.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>socket_object:set_timeout(t)</option>
</term>
<listitem>
<para>
Sets the time, in milliseconds, after which input and
output operations on a socket should time out and
return. The default value is 30,000 (30 seconds). The lowest
allowed value is 10&nbsp;ms, since this is
the granularity of NSE network I/O.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</sect3>
<sect3 id="nse-api-networkio-raw">
<title>Raw packet network I/O</title>
<indexterm><primary>raw packets</primary><secondary>in NSE</secondary></indexterm>
@@ -1460,131 +1133,14 @@ action refer to <xref linkend="nse-tutorial-action"/>.
execution. To use the packet capturing inside your script you have to
create a socket with
<literal>nmap.newsocket()</literal> and later close the socket with <literal>socket_object:close()</literal>&mdash;just
like with the connection-based network I/O. A more detailed description
of the functions for packet capturing follows:
like with the connection-based network I/O.
</para>
<para>
<variablelist>
<varlistentry>
<term><option>socket_object:pcap_open(device, snaplen, promisc,
test_function, bpf)</option>
</term>
<listitem>
<para>
The <literal>pcap_open()</literal> call opens the socket for
packet capturing. The parameters are:</para>
<itemizedlist>
<listitem><para><literal>device</literal>&mdash;the dnet-style interface name of the device you want to capture from</para></listitem>
<listitem><para><literal>snaplen</literal>&mdash;defines the length of each packet you want to capture (similar to the <option>-s</option> option to <command>tcpdump</command>)</para></listitem>
<listitem><para><literal>promisc</literal>&mdash;should be set to <literal>1</literal> if the interface should activate promiscuous mode, and zero otherwise</para></listitem>
<listitem><para><literal>test_function</literal>&mdash;callback function used to compute the <literal>packet hash</literal></para></listitem>
<listitem><para><literal>bpf</literal>&mdash;a string describing a Berkeley packet filter expression (like those provided to <command>tcpdump</command>)</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term><option>socket_object:pcap_register(packet-hash)</option>
</term>
<listitem>
<para>
Starts the listening for incoming packages. The provided
<literal>packet-hash</literal> is a binary string which has to
match the hash returned by the
<literal>test_function</literal> parameter provided to
<literal>pcap_open()</literal>. If you want to receive all
packets, just provide the empty string (<literal>""</literal>).
There has to be a call to <literal>pcap_register()</literal>
before a call to <literal>pcap_receive()</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status, packet_len, l2_data, l3_data = socket_object:pcap_receive()</option>
</term>
<listitem>
<para>
Receives a captured packet. If successful, the return values are:</para>
<itemizedlist>
<listitem><para><literal>status</literal>&mdash;a Boolean with the value <literal>true</literal></para></listitem>
<listitem><para><literal>packet_len</literal>&mdash;the length of the captured packet which was received (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)</para></listitem>
<listitem><para><literal>l2_data</literal>&mdash;data from the second OSI layer (e.g. ethernet headers)</para></listitem>
<listitem><para><literal>l3_data</literal>&mdash;data from the third OSI layer (e.g. IPv4 headers)</para></listitem>
</itemizedlist>
<para>Should an error or timeout occur, while waiting for a packet the
return values are: <literal>nil,error_message,nil,nil</literal>, where
error_message describes the occurred error.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>socket_object:pcap_close()</option>
</term>
<listitem>
<para>Closes the pcap device.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
Receiving raw packets is a great feature, but it is also only the
half job. Now for sending raw packets: To accomplish this NSE has
Receiving raw packets is a great feature, but it is also only half
the job. Now for sending raw packets: To accomplish this NSE has
access to a wrapper around the
<literal>dnet</literal> library.<indexterm><primary>libdnet</primary></indexterm>
Currently NSE has the ability to send raw ethernet frames via the
following API:
</para>
<para>
<variablelist>
<varlistentry>
<term><option>dnet_object=nmap.new_dnet()</option>
</term>
<listitem>
<para>
Creates and returns a new dnet_object, which can be used to
send raw packets.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>dnet_object:ethernet_open(interface_name)</option>
</term>
<listitem>
<para>Opens the interface defined by the provided
<replaceable>interface_name</replaceable> for sending ethernet frames
through it. An error (<quote>device is not valid ethernet
interface</quote>) is thrown in case the provided argument
is not valid.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>dnet_object:ethernet_send(packet)</option>
</term>
<listitem>
<para>
Sends the provided data as ethernet frame across the previously
opened interface. Note that you have to provide the packet
including IP header and ethernet header. If there was no
previous valid call to <literal>ethernet_open()</literal> an
error is thrown (<quote>dnet is not valid opened ethernet
interface</quote>).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>dnet_object:ethernet_close()</option>
</term>
<listitem>
<para>Closes the interface. The only error which may be thrown
is the same as for the <literal>ethernet_send()</literal>
operation.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</sect3>
</sect2>
@@ -1739,7 +1295,7 @@ end
try = nmap.new_try(catch)
try(socket:connect(host.ip, port.number))
result = try(socket:receive_lines(1));
result = try(socket:receive_lines(1))
try(socket:send(result))
</programlisting>
</example>