Scripting nProbe Using Lua

nProbe Professional allows the user to script custom actions and behaviors right before a flow is exported out. Scripted actions and behaviors are executed on a per-protocol basis and require the corresponding plugin. For example, scripting actions and behaviors for HTTP flows requires the HTTP plugin installed and available. Similarly, scripting actions and behaviors for DNS flows requires the DNS plugin to be enabled and available.

Scripts have to be written in Lua language (https://www.lua.org/about.html). Lua is a lightweight scripting language that is dynamically typed, runs by interpreting byte-code with a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping.

Lua scripts are specified using nProbe option –lua. For example, to tell nProbe to execute script dnsSearch.lua located in folder lua/ one can run the following command

./nprobe -i eth1 --lua lua/dnsSearch.lua

But how does nProbe know which function to call? The answer is pretty straightforward: it looks for Lua functions with specific name patterns inside the Lua script received as input.

Lua Functions Naming Convention

nProbe looks for Lua functions that are structured as

check<Protocol>Flow

Every nProbe plugin will inspect the input Lua file and try to find its corresponding function. Plugins must be correctly enabled and set up in order to properly call Lua functions. Plugins that support Lua scripts are outlined in the following table

Protocol Lua Function Name Lua Global Table Name
DHCP checkDHCPFlow dhcp
DNS checkDNSFlow dns
FTP checkFTPFlow ftp
GTPV1 checkGTPV1Flow gtpv1
HTTP checkHTTPFlow http
IMAP checkIMAPFlow imap
POP checkPOPFlow pop
RADIUS checkRADIUSFlow radius
SIP checkSIPFlow sip
SMTP checkSMTPFlow smtp

Every plugin, for every flow – before calling, if available, its corresponding Lua function – pushes into the Lua stack a global table that contains:

  • Flow elements that are common to any flow
  • Additional elements that are peculiar to flows captured with the plugin

Elements are pushed in the global Lua table as pairs Key - Value.

Common Lua Flow Elements

Every flow has some basic elements that are made available, in a global lua table, my plugin. Common information include source and destination ports, for example. The list of common information fields are outlined in the following table

Common Element Name Description
nprobe.pid The process id of the nProbe instance
flow.id A unique integer identification to uniquely represent the flow
flow.from The flow source IP address
flow.to The flow destination IP address
flow.sport The flow source Layer-3 port
flow.dport The flow destination Layer-3 port
flow.duration The duration of the flow in seconds
flow.beginTime The epoch of the flow start time
flow.endTime The epoch of the flow end time
flow.l7_proto A unique integer number to represent the Layer-7 protocol
flow.protocol A unique, standard, integer number to represent the Layer-4 protocol as approved by IANA

Plugin-Specific Lua Flow Elements

These additional fields vary depending on the plugin that called the Lua function. Every plugin prefixes its additional fields with a name that resembles the plugin.

For example, the DNS plugin adds the following fields

Additional DNS Plugin Element Name Description
dns.dns_client The IP address of the client that made the DNS request
dns.as The Autonomous System of the client that made the DNS request
dns.clientcountry The country of the client that made the DNS request
dns.clientcity The city of the client that made the DNS request
dns.query The DNS query performed
dns.answers The DNS answers received

Examples

In the remainder of this section are shown examples of nProbe Lua scripting.

Intercepting DNS Flows

Let’s say a custom action has to be performed right before the export of any DNS flow. Let’s also assume, in the interest of pedagogical clarity, that the custom action consists in printing to the console the global flow Lua table dns that has been pushed in by nProbe. To accomplish the action outlined above it suffices to create a Lua script with the following contents

function checkDNSFlow()
   for k, v in pairs(dns) do
      print('k: '..k..' v: '..v..'\n')
   end
end

The script above iterates over the global dns table and prints all the key-value pairs to the console, one per line. The execution occurs one time for every DNS flow detected, right before exporting the flow. Assuming the script is saved to file dnsSearch.lua under the lua/ directory, then nProbe can be started as follow

./nprobe -i en4 --lua lua/dnsSearch.lua  --dns-dump-dir /tmp

Console logs will confirm the DNS plugin is enabled and that the Lua interpreter correctly parsed dnsSearch.lua:

[...]
[LUA] Successfully interpreted lua/dnsSearch.lua
DNS log files will be saved in /tmp
1 plugin(s) enabled
[...]

At this point it is possible fire a query to a DNS server

$ dig google.it @8.8.8.8

nProbe, right after dig termination, will output to the console the following information

[...]
k: flow.duration v: 1
k: dns.dns_client v: 192.168.2.130
k: flow.sport v: 54209
k: flow.protocol v: 17
k: dns.query v: google.it
k: flow.endTime v: 1466425499
k: flow.beginTime v: 1466425499
k: flow.dport v: 53
k: dns.answers v:
k: dns.as v: 0
k: flow.to v: 8.8.8.8
k: nprobe.pid v: 3278
k: flow.id v: 42
k: flow.from v: 192.168.2.130
[...]