N2OS UserManual SDK 22.0.0
N2OS UserManual SDK 22.0.0
Legal notices
Publication Date
February 2022
Copyright
Copyright © 2013-2022, Nozomi Networks. All rights reserved.
Nozomi Networks believes the information it furnishes to be
accurate and reliable. However, Nozomi Networks assumes no
responsibility for the use of this information, nor any infringement of
patents or other rights of third parties which may result from its use.
No license is granted by implication or otherwise under any patent,
copyright, or other intellectual property right of Nozomi Networks
except as specifically described by applicable user licenses. Nozomi
Networks reserves the right to change specifications at any time
without notice.
Table of Contents
Chapter 2: OpenAPI.............................................................................. 29
Setup............................................................................................................................................30
Errors........................................................................................................................................... 31
Query endpoint............................................................................................................................ 32
CLI endpoint................................................................................................................................ 34
Import CSV endpoint...................................................................................................................35
Import JSON endpoint.................................................................................................................36
Alerts endpoint.............................................................................................................................37
Traces endpoint...........................................................................................................................42
Users endpoint............................................................................................................................ 44
Traces endpoint...........................................................................................................................49
Reports endpoint......................................................................................................................... 53
Report templates endpoint.......................................................................................................... 56
Quarantine endpoint.................................................................................................................... 58
1
Scriptable protocols
Topics: In this manual we will cover the Lua scripting API for building a
custom protocol decoder.
• Setup
• Writing a scriptable protocol
• API reference
| Scriptable protocols | 8
Setup
To add a new scriptable protocol:
1. Copy the Lua script in /data/scriptable_protocols/
2. Configure Guardian with this rule conf.user configure probe scriptable-protocol
<protocol_name> <script_name> in CLI (<script_name> is the name of the file including the
extension)
3. Execute service n2osids stop, the ids process will be restarted automatically.
After this steps the new protocol is loaded in Guardian and will analyze the network traffic.
| Scriptable protocols | 9
function can_handle()
return true
end
From the example we can see that the only mandatory thing to do is to define a function called
can_handle which returns true if it recognize the target protocol.
Of course this implementation is not very useful and it will try to handle every packet so let's write
something more complex to detect and analyze some modbus traffic:
function can_handle()
return packet.source_port() == 502 or packet.destination_port() == 502
end
Here we can see a usage of the API to retrieve the packet ports. In this way the check is a bit more
accurate but it's still insufficient to detect a modbus packet in the real world.
Let's start to do some deep packet inspection:
function can_handle()
if data_size() < 8 then
return false
end
fwd(2)
local has_right_protocol_id = consume_n_uint16() == 0
local expected_length = consume_n_uint16()
WARNING: don't use global variables. Variables defined outside of the can_handle and
update_status functions are global and their status is shared across every session of the same
protocol.
NOTE: the fwd and consume_* functions will move forward the payload pointer.
NOTE: the result of the remaining_size function depends on the position of the payload pointer.
In this example we use the API to inspect the content of the payload. First we check that there are
enough bytes, a modbus packet is at least 8 bytes long. Then we check the port in the same we did
in the previous example, then we skip two bytes with the function fwd and we read the next two 16 bit
integers. We check that the protocol id is zero and that the length written in the packet match with the
remaining bytes in our payload. If every check pass we return true saying to Guardian that the next
packets in this session should be analyzed by this protocol decoder.
| Scriptable protocols | 10
A protocol with just the can_handle function implemented will only create the node and the session in
the network view but the link is still missing from the graph, no additional information will be displayed
in the process view.
To extract more information from the modbus packets we are going to implement the update_status
function:
function get_protocol_type()
return ProtocolType.SCADA
end
function can_handle()
return is_modbus()
end
function update_status()
if not is_modbus() then
return
end
if is_request then
is_packet_from_src_to_dst(true)
set_roles("consumer", "producer")
if fc == 6 then
local address = consume_n_uint16()
execute_update_with_variable(FunctionCode.new(fc), RtuId.new(rtu_id),
"r"..tostring(address), value)
return
end
end
execute_update()
end
NOTE: to avoid duplication we created a is_modbus function from the content of the previous
can_handle function.
NOTE: the is_modbus function has the effect to advance the payload pointer by 6 bytes, so when can
directly read the rtu_id without further payload pointer manipulations.
NOTE: we defined the get_protocol_type function to define the protocol type
In this example of update_status we read more data from the payload and we decode the
write single register request. We can understand the direction of the communication so we call
is_packet_from_src_to_dst with true to notify Guardian and create a link and we call
set_roles to set the roles on the involved nodes.
To insert a variable in Guardian there is the execute_update_with_variable function, it takes 4
arguments: the function code, the rtu id, the variable name and the value. The FunctionCode and
RtuId objects can be constructed from a string or a number, the DataValue object can be constructed
with the empty constructor and then filled with the available information.
| Scriptable protocols | 11
With the next example we cover a more complex case and we store some data in the session to handle
a request and a response:
local PENDING_FC = 1
local PENDING_START_ADDR = 2
local PENDING_REG_COUNT = 3
function update_status()
if not is_modbus() then
return
end
rwd()
if is_request then
is_packet_from_src_to_dst(true)
set_roles("consumer", "producer")
session.set_pending_request_number(transaction_id, PENDING_FC, fc)
if fc == 3 then
if remaining_size() < 4 then
return
end
session.set_pending_request_number(transaction_id, PENDING_START_ADDR,
start_addr)
session.set_pending_request_number(transaction_id, PENDING_REG_COUNT,
registers_count)
end
else
is_packet_from_src_to_dst(false)
local req_fc = session.read_pending_request_number(transaction_id,
PENDING_FC)
if fc == req_fc then
if fc == 3 then
local start_addr = session.read_pending_request_number(transaction_id,
PENDING_START_ADDR)
local reg_count = session.read_pending_request_number(transaction_id,
PENDING_REG_COUNT)
session.close_pending_request(transaction_id)
if remaining_size() ~= byte_count or
reg_count * 2 ~= remaining_size() then
send_alert_malformed_packet("Packet is too small")
return
end
for i = 0, reg_count - 1, 1 do
local value = DataValue.new()
value.value = consume_n_uint16()
| Scriptable protocols | 12
value.cause = DataCause.READ_SCAN
value.type = DataType.ANALOG
value.time = packet.time()
execute_update_with_variable(FunctionCode.new(fc),
RtuId.new(rtu_id),
"r"..tostring(start_addr+i),
value)
end
return
end
end
end
execute_update()
end
This time we are focusing on the read holding register function code, to understand the communication
and create a variable we need to analyze both the request and the response and we need to keep
some data from the request and use it in the response. To achieve this we can use the functions
provided by the session object.
| Scriptable protocols | 13
API reference
Data types
Class FunctionCode
Constructors • FunctionCode.new(<string>)
• FunctionCode.new(<number>)
Class RtuId
Constructors • RtuId.new(<string>)
• RtuId.new(<number>)
Class DataValue
Constructors • DataValue.new()
Class Variable
Methods • set_label(<string>)
Class Node
Methods • set_property(<key>, <value>)
• get_property(<key>)
• delete_property(<key>)
• set_label(<label>)
Enum DataCause
Values • DataCause.READ_SCAN
• DataCause.READ_CYCLIC
• DataCause.READ_EVENT
• DataCause.WRITE
Enum DataType
| Scriptable protocols | 14
Values • DataType.ANALOG
• the Analog type represents a floating point number
• DataType.DIGITAL
• the Digital type represents a boolean type and can be either 0 or 1
• DataType.BITSTRING
• the Bitstring type represents a raw value in the form of a sequence of
0 and 1, e.g. "00101110"
• DataType.STRING
• the String type represents a value in the form of a sequence of
printable characters
• DataType.DOUBLEPOINT
• the Double Point type represents a boolean value with an additional
degree of redundancy. It is commonly used in protocols such as
DNP3, IEC 104 or IEC 61850
• DataType.TIMESTAMP
• the Timestamp type represents a point in time in the format of
milliseconds from the epoch
• Note: Only ANALOG, DIGITAL and DOUBLEPOINT types are kept in
consideration by the Process Learning Engine when detecting deviations
from the baseline.
Enum ProtocolType
Values • ProtocolType.SCADA
• ProtocolType.NETWORK
• ProtocolType.IoT
Functions
Syntax data(<index>)
Parameters • index: the position of the byte to read, starting from 0
Description Return the value of the byte from the specified position, return 0 if index is
out of bounds
Syntax data_size()
Description Return the total size of the payload
Syntax remaining_size()
Description Return the size of the payload from the pointer to the end. The result
depends on the usage of functions fwd(), rwd() and consume_*().
Syntax fwd(<amount>)
Parameters • amount: the number of bytes to skip
Syntax rwd()
Description Move the payload pointer to the beginning of the payload.
| Scriptable protocols | 15
Syntax read_uint8()
Description Read an unsigned 8bit integer at the payload pointer position.
Syntax read_int8()
Description Read an signed 8bit integer at the payload pointer position.
Syntax read_n_uint16()
Description Read a network order unsigned 16bit integer at the payload pointer position.
Syntax read_h_uint16()
Description Read a host order unsigned 16bit integer at the payload pointer position.
Syntax read_n_int16()
Description Read a network order signed 16bit integer at the payload pointer position.
Syntax read_h_int16()
Description Read a host order signed 16bit integer at the payload pointer position.
Syntax read_n_uint32()
Description Read a network order unsigned 32bit integer at the payload pointer position.
Syntax read_h_uint32()
Description Read a host order unsigned 32bit integer at the payload pointer position.
Syntax read_n_int32()
Description Read a network order signed 32bit integer at the payload pointer position.
Syntax read_h_int32()
Description Read a host order signed 32bit integer at the payload pointer position.
Syntax read_n_uint64()
Description Read a network order unsigned 64bit integer at the payload pointer position.
Syntax read_h_uint64()
Description Read a host order unsigned 64bit integer at the payload pointer position.
Syntax read_n_int64()
Description Read a network order signed 64bit integer at the payload pointer position.
Syntax read_h_int64()
Description Read a host order signed 64bit integer at the payload pointer position.
Syntax read_n_float()
Description Read a network order float at the payload pointer position.
| Scriptable protocols | 16
Syntax read_h_float()
Description Read a host order float at the payload pointer position.
Syntax read_n_double()
Description Read a network order double at the payload pointer position.
Syntax read_h_double()
Description Read a host order double at the payload pointer position.
Syntax read_string()
Description Read a string at the payload pointer position until the null terminator.
Syntax read_string_with_len(str_len)
Description Read a string at the payload pointer position for str_len bytes.
Syntax consume_uint8()
Description Read an unsigned 8bit integer at the payload pointer position and move the
pointer after the data.
Syntax consume_int8()
Description Read an signed 8bit integer at the payload pointer position and move the
pointer after the data.
Syntax consume_n_uint16()
Description Read a network order unsigned 16bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_uint16()
Description Read a host order unsigned 16bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_int16()
Description Read a network order signed 16bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_int16()
Description Read a host order signed 16bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_uint32()
Description Read a network order unsigned 32bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_uint32()
Description Read a host order unsigned 32bit integer at the payload pointer position and
move the pointer after the data.
| Scriptable protocols | 17
Syntax consume_n_int32()
Description Read a network order signed 32bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_int32()
Description Read a host order signed 32bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_uint64()
Description Read a network order unsigned 64bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_uint64()
Description Read a host order unsigned 64bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_int64()
Description Read a network order signed 64bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_int64()
Description Read a host order signed 64bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_float()
Description Read a network order float at the payload pointer position and move the
pointer after the data.
Syntax consume_h_float()
Description Read a host order float at the payload pointer position and move the pointer
after the data.
Syntax consume_n_double()
Description Read a network order double at the payload pointer position and move the
pointer after the data.
Syntax consume_h_double()
Description Read a host order double at the payload pointer position and move the
pointer after the data.
Syntax consume_string()
Description Read a string at the payload pointer position until the null terminator and
move the pointer after the data.
Syntax consume_string_with_len(str_len)
Description Read a string at the payload pointer position for str_len bytes and move
the pointer after the data.
| Scriptable protocols | 18
Description Compute the CRC16 of the remaining payload according to the input
parameters. The input parameters for CRC functions can be easily found
online. For example, to get a CRC16/DNP the parameters are: 0x3D65,
0x0000, 0xFFFF, true, true
Description Compute the CRC32 of the remaining payload according to the input
parameters. The input parameters for CRC functions can be easily
found online. For example, to get a plain CRC32 the parameters are:
0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true
Description Set the roles of the involved nodes, valid values are: "consumer",
"producer", "historian", "terminal", "web_server", "dns_server", "db_server",
"time_server", "other"
Syntax set_source_type(<node_type>)
| Scriptable protocols | 19
Description Set the type of the source node, valid values are: "switch", "router", "printer",
"group", "OT_device", "broadcast", "computer"
Syntax variables_are_on_client()
Parameters
Description Notify to Guardian that the variables should be added to the client node
syntax is_packet_from_src_to_dst(<is_from_src>)
parameters • is_from_src: true is the direction is from src to dst, false otherwise
description notify Guardian about the direction of the packet, this function must be
called to obtain a link creation
syntax execute_update()
parameters
description notify Guardian about the a packet, at least one variant of execute_update
should be called for every packet
description notify Guardian about the a packet with a function code and a rtu id
description notify Guardian about the a packet with a function code, a rtu id, a variable
name and a variable value
description notify Guardian about the a packet with a function code, a rtu id, a variable
name, a variable value and a function that give the possibility to directly
access the variable
| Scriptable protocols | 20
syntax AlertFactory.new().new_net_device()
description raise an alert of type VI:NEW-NET-DEV
syntax AlertFactory.new().firmware_change()
description raise an alert of type SIGN:FIRMWARE-CHANGE
syntax AlertFactory.new().protocol_error(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().wrong_time(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().sync_asked_again(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().protocol_flow_anomaly(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().variable_flow_anomaly(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().dhcp_request(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().invalid_ip(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().new_arp(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().duplicated_ip(<reason>)
parameters • reason: a message to be displayed in the alert
| Scriptable protocols | 21
syntax AlertFactory.new().link_reconnection(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().rst_from_producer(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().tcp_syn(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().tcp_syn_flood(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().tcp_flood(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().protocol_flood(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().mac_flood(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().network_scan(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().cleartext_password(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().ddos_attack(<reason>)
| Scriptable protocols | 22
syntax AlertFactory.new().unsupported_func(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().illegal_parameters(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().weak_password(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().malware_detected(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().unknown_rtu(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().missing_variable(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().scada_injection(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().new_variable(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().new_variable_value(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().device_state_change(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().configuration_change(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().malicious_protocol(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().weak_encryption(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().malformed_ot_packet(<triggerId>,
<reason>)
parameters • triggerId: identifier of the triggering engine entity
• reason: a message to be displayed in the alert
syntax AlertFactory.new().malformed_network_packet(<triggerId>,
<reason>)
parameters • triggerId: identifier of the triggering engine entity
• reason: a message to be displayed in the alert
syntax AlertFactory.new().suspicious_time(<triggerId>,
<reason>)
parameters • triggerId: identifier of the triggering engine entity
• reason: a message to be displayed in the alert
syntax AlertFactory.new().new_node(<nodeId>)
parameters • nodeId: identifier of the node
syntax AlertFactory.new().new_target_node(<nodeId>)
parameters • nodeId: identifier of the node
syntax AlertFactory.new().new_node_malicious_ip(<nodeId>,
<threatName>)
parameters • nodeId: identifier of the node
• threatName: the name of the threat
syntax AlertFactory.new().new_mac_vendor(<nodeId>,
<macAddress>)
parameters • nodeId: identifier of the node
• macAddress: MAC Address
syntax AlertFactory.new().malicious_domain(<domain>,
<threatName>, <reason>)
parameters • domain: the malicious domain
• threatName: the name of the threat
• reason: a message to be displayed in the alert
syntax AlertFactory.new().configuration_mismatch(<nodeId>,
<triggerId>, <reason>)
parameters • nodeId: identifier of the node
• triggerId: identifier of the triggering engine entity
• reason: a message to be displayed in the alert
syntax AlertFactory.new().multiple_ot_device_reservations(<sNodeId>,
<dNodeId>, <protocolId>, <bpfFilter>, <protocolType>,
<reason>)
| Scriptable protocols | 25
syntax AlertFactory.new().multiple_unsuccessful_logins(<sNodeId>,
<dNodeId>, <protocolId>, <bpfFilter>, <protocolType>,
<reason>)
parameters • sNodeId: identifier of the source node
• dstNodeId: identifier of the destination node
• protocolId: identifier of the protocol
• bpfFilter: BPF filter
• protocolType: type of the protocol according to the ProtocolType type
• reason: a message to be displayed in the alert
syntax AlertFactory.new().multiple_access_denied(<sNodeId>,
<dNodeId>, <protocolId>, <bpfFilter>, <protocolType>,
<reason>)
parameters • sNodeId: identifier of the source node
• dNodeId: identifier of the destination node
• protocolId: identifier of the protocol
• bpfFilter: BPF filter
• protocolType: type of the protocol according to the ProtocolType type
• reason: a message to be displayed in the alert
syntax send_alert_malformed_packet(<reason>)
parameters • reason: a message to be displayed in the alert
description notify a captured URL to the system. Note that captured URLs need to
be explicitly enabled by specifying the vi captured_urls enabled
configuration setting.
description notify a link event to the system. Note that link events need to be explicitly
enabled by specifying the vi link_events enabled configuration
setting.
syntax packet.source_id()
description return the source node id
syntax packet.destination_id()
description return the destination node id
syntax packet.source_ip()
description return the source node ip
syntax packet.destination_ip()
description return the destination node ip
syntax packet.source_mac()
description return the source node mac
syntax packet.destination_mac()
description return the destination node mac
syntax packet.source_port()
description return the source node port
syntax packet.destination_port()
description return the destination node port
syntax packet.is_ip()
description return true if the packet is an ip packet
| Scriptable protocols | 27
syntax packet.transport_type()
description return the transport layer type, can be "tcp", "udp", "ethernet", "icmp" or
"unknown"
syntax packet.source_node()
description returns the source node
syntax packet.destination_node()
description returns the destination node
syntax packet.time()
description return the packet time
syntax session.has_pending_request(<request_id>)
parameters • request_id: a number used to uniquely identify the request
description return true if there are values stored with the request_id
description return true if there are values stored with the request_id and key
syntax session.close_pending_request(<request_id>)
parameters • request_id: a number used to uniquely identify the request
description close the pending request and delete the associated data
syntax log_d(<msg>)
parameters • msg: the message to log
syntax log_e(<msg>)
parameters • msg: the message to log
2
OpenAPI
Topics: In this chapter we will cover our OpenAPI implementation, which
consists of an HTTP endpoint for executing custom queries.
• Setup
Open API methods that change appliance data produce audit
• Errors
logs, for example this happens when a new user is added through
• Query endpoint the Open API or an alert is acknowledged. By default, read only
• CLI endpoint operation don't produce audit logs. It's possible to change this
• Import CSV endpoint behavior and have GET Open API methods produce audit logs by
• Import JSON endpoint specifying the following cli command: conf.user configure
• Alerts endpoint open_api audit get enabled true.
• Traces endpoint
• Users endpoint
• Traces endpoint
• Reports endpoint
• Report templates endpoint
• Quarantine endpoint
| OpenAPI | 30
Setup
To perform a call to the endpoint you need to pass authentication credentials as headers, the examples
provided use Postman, an HTTP client.
Remember to use your Nozomi Networks Solution's web interface IP instead of the example one.
Nozomi Networks suggests to create dedicated users for OpenAPI usage, with minimal permissions
necessary to access the required data sources.
Errors
If you fail to provide valid authentication credentials the expected error will be 401 Unauthorized, as
shown below.
If you ask for a data source that does not exist you will receive a proper message in the error field.
Query endpoint
You can manipulate data sources through the use of queries, which are commands piped one after
another. Please refer to the Queries chapter of the User Manual, or head over to /#/query in your
Nozomi Networks Solution web interface to see some examples.
Requirements and Restrictions
1. A user having the permission to execute api.
2. The result contains the list of items queried.
3. It's possible, and recommended, to use pagination adding page and count params.
4. The page param is the number of the page to return, the count is the dimension of the page.
5. If count is not provided the default value is 100 thousand, if page is not provided default page
number is 1.
6. If the provided count value is higher than 100 thousand, no more than 100 thousand items will
be returned.
For example, to see how many nodes are in the system, call the following URL:
https://10.0.1.10/api/open/query/do?query=nodes | count
As you can see there's no need to escape the query, let's see a more complex one:
https://10.0.1.10/api/open/query/do?query=nodes | where_link protocol ==
http | head 5. In the image we've used Postman's interface to collapse the results so you could
clearly see it's five as we wanted.
| OpenAPI | 33
CLI endpoint
You can apply changes to the system by issuing CLI commands over this endpoint.
The endpoint is located at /api/open/cli and requires to be invoked with the cmd parameter with a
POST.
CLI commands allow to change virtually anything inside the system, please refer to the Configuration
section of the User Manual for a more complete reference.
| OpenAPI | 35
label
firmware_version
vendor
product_name
serial_number
os
mac_address
label
firmware_version
vendor
product_name
serial_number
os
mac_address
Alerts endpoint
A POST to /api/open/alerts/close request allows you to close a group of alerts passed as a
json list of ids in the body of the request. You must also pass as parameter the close_action field
containing delete_rules or learn_rules in case you want to close alerts as security or as change.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. The input data must be a JSON dictionary containing a ids key whose value must be an array of
alert 'id' and a 'close_action' constant field.
3. In case the request body does not adhere to the format described above the call returns a 422
error.
4. In case the request is well formed, the result will contain the id of the job in charge of the task. You
can monitor the status of the job via the alerts/close/status/:id API.
{
"ids": ["uuid"],
"close_action": "learn_rules"
}
{
"data": [
{
"id": "uuid",
"ack": true
}
]
}
2. As last parameter of the path you need to specify the id of the job returned by the alerts/ack
API.
3. The result will contain the status of the job, which can have one of the following values: SUCCESS,
PENDING or FAIL
4. In case of FAIL status, the error field will report the error reason.
A GET to /api/open/alerts/all request allows you to get the IDs of alerts matching a condition.
You can specify a filter query in the query parameter and an additional parameter named has_trace
to get the status of the corresponding trace.
Requirements and Restrictions
1. The authenticated user has to belong to a group having admin role or with Alerts section enabled.
2. The query parameter should be in Nozomi Networks Query Language format, where the table
name is implicit, i.e. alerts.
3. The has_trace parameter type is boolean.
4. If no alert matches the specified conditions, a 404 error will be returned.
A GET to /api/open/alerts/:id/trace request allows you to get a file containing the trace of the
alert, whose id is specified as a parameter.
| OpenAPI | 40
Traces endpoint
A GET to /api/open/traces/all request allows you to get the traces matching a condition. You
can specify a filter query in the query parameter. You have to specify the operation parameter
defining the requested operation. So far the only allowed value for operation is download.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. As a result you will get a file containing the trace or the traces filtered according to the specified
condition
3. If the trace is still in progress or it is not found, a 422 error with a proper reason string will be
returned.
A GET to /api/open/traces/bpf-filter request allows you to select traces using a BPF filter.
This call returns a job id, while the actual disk search is performed asynchronously. The search will
return a list of the first PCAP traces that match the filter. The maximum number of PCAP traces is 50
by default and can be configured with the open_api bpf_filter traces_limit setting. There
can’t be more than a limited number of concurrent BPF trace searches at a time. This number is 2
by default and can be configured with the open_api bpf_filter max_concurrent_searches
setting.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
| OpenAPI | 43
Users endpoint
A GET to /api/open/users allows you to get a list of all the users.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. The result contains the list of all users.
3. It's possible to use pagination adding page and count params
4. The page param is the number of the page to return, the count is the dimension of the page.
5. If count is nil or 0 the default value will be 100, if page is nil or 0 the request will not be paginated.
6. This api is disabled by default; to enable it add conf.user configure api users enabled
true in CLI.
A GET to /api/open/user_groups allows you to get a list of all the user groups.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. The result contains the list of all user groups.
3. It's possible to use pagination adding page and count params
4. The page param is the number of the page to return, the count is the dimension of the page.
5. If count is nil or 0 the default value will be 100, if page is nil or 0 the request will not be paginated.
| OpenAPI | 45
A GET to /api/open/users/:id allows you to get the user having the id passed as path parameter.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. As last parameter of the path you need to specify the id of the user.
3. The result will contain the user
4. In case the user with that id is not found you'll get a 404.
A DELETE to /api/open/users/:id allows you to delete the user having the id passed as path
parameter.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. As last parameter of the path you need to specify the id of the user.
3. The result will contain the status code 204 for success else the error code
4. In case the user with that id is not found you'll get a 404.
| OpenAPI | 46
{
"username": "user_under_test22",
"password": "aValidP4ss!",
"user_group_ids": [2],
"strategy": "local",
"is_suspended": false,
"should_update_pwd": false,
"ssh_keys": "an_ssh_key",
"allow_root_ssh": true
}
| OpenAPI | 47
A PUT to /api/open/users/:id allows you to update the user with the id passed as path param.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. As last parameter of the path you need to specify the id of the user you want to update.
3. The input must be a JSON dictionary containing the user field properly populated
4. If the update goes well the call return 204 (No content) response
5. You can't update the password here because updating password is not idempotent so you can't do
via PUT.
6. The fields you can update are listed below.
7. user_group_ids must contain at least one valid id.
{
"username": "user_under_test22",
"strategy": "local",
"user_group_ids": [1,2],
"is_suspended": false,
"should_update_pwd": false,
"ssh_keys": "a_new_key",
"allow_root_ssh": true
}
{
"password": "4ValidP4ssw0rd!"
}
Traces endpoint
A GET request to /api/open/pcaps request allows you to get the list of all traces available on the
machine. You can pass the ID of a given trace to get information only for that trace.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role or with Upload traces section
enabled.
2. In case the request body does not adhere to the format described above, the call returns a 422
error.
3. If you specify an ID of a trace that does not exist, the call returns a 404 error.
4. If the request is accepted, the result will contain useful information on the retrieved trace.
1. The authenticated user must be in a group having admin role or with Upload traces section
enabled.
2. In case the request body does not adhere to the format described above, the call returns a 422
error.
3. If you specify an ID od a trace that does not exist, the call returns a 404 error.
4. If the request is accepted, the trace will be deleted.
A POST request to /api/open/pcaps/upload request allows you to upload a trace passed as a file
in the body of the request.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role or with Upload traces section
enabled.
2. The trace should be passed in the form-data section of the request body.
3. In case the request body does not adhere to the format described above, the call returns a 422
error.
4. If the file sent in the request is not a valid trace, the call returns a 422 error along with an error
reason describing the cause of the validation failure.
5. If the request is accepted, the trace will be uploaded.
A POST request to /api/open/pcaps/import request allows you to import a trace file that is
already present in the machine.
| OpenAPI | 51
A PATCH request to /api/open/pcaps request allows you to replay a trace that has been previously
uploaded or imported.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role or with Upload traces section
enabled.
2. The trace should be present in the list of the available traces returned by the GET request to /api/
open/pcaps.
3. The id parameter of the request should contain the ID of the trace.
4. The use_packet_time boolean parameter should be set to true if you want to use the time of
the packets; false otherwise.
5. The data_to_reset_before_play parameter should be set to {} if you do not want to reset
data before playing the trace. Otherwise, you need to specify a JSON dictionary with the sections
you want to reset, for example {"alerts": true, "vi": true}. The list of all available
sections is the following:
• alerts_data
• assertions
• learning
• network_data
• process_data
• queries
• smart_polling_data
• timemachine_data
• traces_data
| OpenAPI | 52
• vi_data
• vulnerability_data
The list above reflects the options available for Data reset in the UI.
6. In case the request body does not adhere to the format described above, the call returns a 422
error.
7. If you specify an ID of a trace that does not exist, the call returns a 404 error.
8. If the request is accepted, the trace will be replayed.
A PATCH request to /api/open/pcaps/note request allows you to change the note field of a trace.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role or with Upload traces section
enabled.
2. The trace should be present in the list of the available traces returned by the GET request to /api/
open/pcaps.
3. The id parameter of the request should contain the ID of the trace.
4. The note parameter of the request should contain the text you want to change.
5. In case the request body does not adhere to the format described above, the call returns a 422
error.
6. If the request is accepted, the note will be changed.
Reports endpoint
A GET to /api/open/reports allows you to get a list of all the reports generated.
Requirements and Restrictions
1. A user having the permission to execute api.
2. The result contains the list of all the reports.
3. It's possible to use pagination adding page and count params
4. The page param is the number of the page to return, the count is the dimension of the page.
5. If count is nil or 0 the default value will be 100, if page is nil or 0 the request will not be paginated.
6. You can filter the result passing a template_name as query param having value the report
templates name you want filtering on.
A GET to /api/open/reports/:id allows you to get the report having the id passed as path
parameter.
Requirements and Restrictions
1. A user having the permission to execute api.
2. As last parameter of the path you need to specify the id of the report.
3. The result will contain the report.
4. In case the report with that id is not found you'll get a 404.
| OpenAPI | 54
A GET to /api/open/reports/:id/files allows you to download the report having the id passed
as path parameter.
Requirements and Restrictions
1. A user having the permission to execute api.
2. As middle parameter of the path you need to specify the id of the report.
3. The report download will be triggered.
4. In case the report with that id is not found you'll get a 404.
3. In case the request is well formed return a 202 response with the id of the job is taking care of teh
request.
A GET to api/open/reports/jobs/1/status allows you to get the create report job result.
Requirements and Restrictions
1. A user having the permission to execute api.
2. As parameter of the path you need to specify the id of the job.
3. The result will contain the job status
A GET to /api/open/report_templates/:id allows you to get the report template having the id
passed as path parameter.
Requirements and Restrictions
1. A user having the permission to execute api.
2. As last parameter of the path you need to specify the id of the report template.
3. The result will contain the report template.
4. In case the report with that id is not found you'll get a 404.
| OpenAPI | 57
Hint: as shown in the top part of the previous screenshot, the file parameter to be used with the
request can be found in the properties field of SIGN:MALWARE-DETECTED alerts.
Chapter
3
Data Model
Topics: In this chapter we will cover our Data Model reference for query
entities.
• Data Model reference
| Data Model | 60
alerts
Alerts represent events raised by the Guardian
appliances
This query source contains any kind of appliance on the CMC and Remote Collectors -- if any -- on the
Guardian
assertions
An assertion represent an automatic check against other query sources
assets
Assets represent a local, physical system to care about, and can be composed of one or more Nodes
captured_logs
Logs captured passively over the network
captured_urls
URLs and other protocol calls found in the network. Access to files, requests to DNS, requested URLs
and other are available in this query source.
function_codes
Function Codes used in the environment
health_log
Health-related events about the system - like high resource utilization or hardware-related issues or
events
link_events
Events that can occurr on a Link, like it being available or not
links
Links are protocol relations between two Nodes and with a specific protocol. They model the interaction
between Nodes
node_cpe_changes
On the event of update of a CPE, an entry in this query source is created to keep track of software
updates or better detection of software
node_cpes
List CPEs (Common Platform Enumeration), that is software or component connected to a specific
Node in the system
node_cves
Vulnerabilities matched against current CPEs
node_points
Data points polled via Smart Polling from monitored Nodes
nodes
List of Nodes, where is node is an L2 or L3 or other entity able to speak some protocol
report_files
Generated reports available for consultation
sessions
Live, mostly open Sessions between Nodes. A Session is a specific application-level connection
between nodes. A Link can hold one or more Session at a given time.
sessions_history
Archived Sessions. See the sessions query source for more information
variable_history
History of values for Variables where history has been enabled
variables
Variables extracted via DPI from the monitored system
4
Data Integrations Best Practices
Topics: This chapter details the best practices when using Nozomi Networks
data integration that is obtained via Syslog integration or OpenAPI
• Data Sources for Integration calls.
• Nozomi Syslog Data Types
• OpenAPI Data
• Certify Your Integration with
Nozomi
| Data Integrations Best Practices | 80
cs3 cs3Label Id: The Alert ID (not Alert Type ID) of the alert in the
Nozomi system
Ensure that your integration recognizes these custom labels and deals with them appropriately.
Syslog Messages
Alert Events
There are many alert types in the Nozomi environment. The N2OS User Manual contains a full
reference of Alert Types.
Alert Events in CEF have the following format, e.g.:
| Data Integrations Best Practices | 81
Note the highlighted part of the Alert message. This is the Alert Type ID. This should be used as
the key for performing searches once Nozomi syslog events have been ingested into the integration
platform.
Best Practice: Ensure that your parsing logic extracts the appropriate data. If you are integrating with
CEF messages, a CEF parser must be used. Do not use regular expressions. This will ensure the
integration integrity in the future. When using the correct parser for the data that is expected, be sure to
test different inputs to ensure that data is correctly extracted from the messages.
Health Events
Health Events in CEF have the following format, e.g.:
Note the highlighted part of the Health message. This is the Health Type ID. This should be used as
the key for performing searches once Nozomi syslog events have been ingested into the integration
platform.
Best Practice: Ensure that your parsing logic extracts the appropriate data. If you are integrating with
CEF messages, a CEF parser must be used. Do not use regular expressions. This will ensure the
integration integrity in the future. When using the correct parser for the data that is expected, be sure to
test different inputs to ensure that data is correctly extracted from the messages.
Audit Events
Audit Events in CEF have the following format, e.g.:
| Data Integrations Best Practices | 82
Note the highlighted part of the Audit message. This is the Audit Type ID. This should be used as
the key for performing searches once Nozomi syslog events have been ingested into the integration
platform.
Best Practice: Ensure that your parsing logic extracts the appropriate data. If you are integrating with
CEF messages, a CEF parser must be used. Do not use regular expressions. This will ensure the
integration integrity in the future. When using the correct parser for the data that is expected, be sure to
test different inputs to ensure that data is correctly extracted from the messages.
OpenAPI Data
API Users
Nozomi recommends the practice of creating a user specifically for the purposes of api access. This
provides a demarcation of responsibilities that is straight forward for auditing and traceability.
Best Practice: Create a user specifically for accessing the OpenAPI.
Authentication
Each call to one of the OpenAPI methods requires authentication. Currently, the OpenAPI supports
Basic Authentication. So, for example using CURL, if you have a Username and Password for your api
user, then you will pass the following header along with your query:
-H "Authorization: Basic <AUTH_TOKEN>"
Where <AUTH_TOKEN> is the base64 encoding of Username:Password.
Note that the language and method of implementation (e.g. CURL vs Java) will dictate how the
specifics of the Basic Authentication are performed.
Note: In case of querying the OpenAPI for data, the -k –user Username:Password option may be
used instead for Basic Authentication.
{
"header": [
All of the headers…
],
"result": [
{ First Node data },
{ Second Node data }
],
"total": 2
}
{
"nodes": [
{
"ip": "1.2.3.8",
"label": "JSON_Uploaded_Asset_1",
"mac_address": "00:00:00:11:11:11",
"firmware_version": "1.2.3",
"product_name": "ACME_PLC_2",
"serial_number": "1-789A10-2",
"vendor": "ACME"
| Data Integrations Best Practices | 84
},
{
"ip": "1.2.3.3",
"label": "JSON_Uploaded_Asset_2",
"mac_address": "00:00:00:11:11:15",
"firmware_version": "1.2.2",
"product_name": "ACME_PLC_1",
"serial_number": "1-789A10-6",
"vendor": "ACME"
}
]
}
Depending on your CURL implementation, the file may have to be submitted using -d as in the example
below.
The following command will upload these assets into the Guardian or CMC:
Import Commands
Downloading traces
Traces associated with an alert can be downloaded via the api as well. We will need the alert ID in
order to accomplish this. The following command will download a trace associated with an alert ID
<YourAlertID> to the file specified by <YourTraceFile>:
curl -k -X GET https://<YourHost>/api/open/alerts/<YourAlertID>/trace -H
"Authorization: Basic <AUTH_TOKEN>" -H "Content-Type: application/js on" --
output <YourTraceFile>